[英]How to do recursive search of Folders & Files using producer/consumer queues?
我想先搜索目錄,然后搜索其中的文件,搜索關鍵字。
我知道我需要兩個類,生產者 class 和消費者 class,但我不知道如何使用 c# 生產者/消費者隊列進行搜索?
public class Program
{
private static void Main()
{
Queue<File> searchFile = new Queue<File>();
Queue<Directory> searchDirectory = new Queue<Directory>();
new Thread(searchDirectory).Start();
for (int i = 0; i < 3; i++)
new Thread(searchFile).Start();
}
}
最初的問題:
項目編號 2 的問題是您正在處理多線程的最大瓶頸之一 - 即磁盤 IO。 通過實現多個工作線程來執行磁盤 IO(在標准 HDD 設備上)將一無所獲。
詳細說明您要做什么(請舉例說明)。 可能會有更好的過程。
首先, Directory
是一個 static class 所以你不能一個集合。 您將需要改用DirectoryInfo
。 其次,我將使用一個包含DirectoryInfo
實例的隊列。 然后可以枚舉這些文件作為處理單個文件夾的一部分。
這是我使用生產者-消費者模式的方法。 此實現使用BlockingCollection
class 作為阻塞隊列的實現。 阻塞隊列在生產者-消費者模式中非常有用,因為它們抽象了幾乎所有的生產者-消費者細節。
public class Searcher
{
private BlockingCollection<DirectoryInfo> m_Queue = new BlockingCollection<DirectoryInfo>();
public Searcher()
{
for (int i = 0; i < NUMBER_OF_THREADS; i++)
{
var thread = new Thread(Run);
thread.IsBackground = true;
thread.Start();
}
}
public void Search(DirectoryInfo root)
{
m_Queue.Add(root);
}
private void Run()
{
while (true)
{
// Wait for an item to appear in the queue.
DirectoryInfo root = m_Queue.Take();
// Add each child directory to the queue. This is the recursive part.
foreach (DirectoryInfo child in root.GetDirectories())
{
m_Queue.Add(child);
}
// Now we can enumerate each file in the directory.
foreach (FileInfo child in root.GetFiles())
{
// Add your search logic here.
}
}
}
}
我應該指出,大多數磁盤以更加序列化的方式工作,因此嘗試搜索文件的多個線程可能不會給你帶來很多好處,除非你的邏輯的 CPU 綁定部分很廣泛。
正如其他海報所暗示的那樣,嘗試執行 IO 的多個線程將導致問題。 但是,它們可以用於構建完整的目錄隊列(如果它非常深),然后是一個單獨的線程來在文件上執行正則表達式。 有點像這樣:
class Program
{
static void Main(string[] args)
{
ConcurrentQueue<DirectoryInfo> concurrentQueue = new ConcurrentQueue<DirectoryInfo>();
GetAllDirectories(new DirectoryInfo(@"C:\local\oracle"), concurrentQueue);
Action action = () =>{
const string toFind = "ora";
DirectoryInfo info;
while(concurrentQueue.TryDequeue(out info))
{
FindInFile(toFind, info);
}
};
Parallel.Invoke(action, action, action, action);
Console.WriteLine("total found " + _counter);
Console.ReadKey();
}
static int _counter = 0;
static void FindInFile(string textToFind,DirectoryInfo dirInfo)
{
var files =dirInfo.GetFiles();
foreach(FileInfo file in files)
{
using (StreamReader reader = new StreamReader(file.FullName))
{
string content = reader.ReadToEnd();
Match match = Regex.Match(content, textToFind, RegexOptions.Multiline);
if(match.Success)
{
Interlocked.Increment(ref _counter);
Console.WriteLine(file.FullName + " found " + match.Captures.Count);
foreach(var t in match.Captures)
{
Console.WriteLine("-------------> char index" + match.Index);
}
}
}
}
}
internal static void GetAllDirectories(DirectoryInfo root, ConcurrentQueue<DirectoryInfo> values)
{
foreach (var di in root.GetDirectories())
{
GetAllDirectories(di, values);
values.Enqueue(di);
}
}
}
我已經編輯了這篇文章(正在等待同行評審)。 如果它確實獲得批准,我已經編輯了代碼以修復 scope 和拼寫錯誤的基本問題,但我認為您還沒有准備好使用多線程,更不用說生產者 - 消費者隊列(上帝知道我已經涉足多線程線程一段時間,我最終還是弄亂了我的實現,但那可能只是我。)。
您應該首先熟悉范圍和多線程。 特別是閱讀對實現成功的多線程解決方案至關重要的鎖定機制/並發問題。
其次,正如 IAbstract 建議的那樣,確實使用互斥體/信號量實現多個線程,以通過多線程獲得性能以及獲得所需的生產者-消費者隊列。
此外,如果您覺得舒服,您還可以查看最新的 Async CTP1 DataFlow 庫,該庫使用 Tasks Parallel Library 對該模式提供最新支持。 或者,您可以使用BlockingCollection
來實現此模式。
Stackoverflow 也有一些圍繞你的問題的問題,並給出了一些很好的答案。 只需搜索“生產者-消費者”即可閱讀它們
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.