2011-06-09 23 views
3

我想首先搜索目录,然后搜索其中的文件,找到关键字。如何使用生产者/消费者队列对文件夹和文件进行递归搜索?

我知道我需要两个类,生产者类&消费者类,但我不知道如何使用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(); 
    } 
} 
+0

这是一个非常好的问题。 – 2011-06-09 18:13:51

回答

1

最初的问题:

  1. 您使用的是相同的 变量名相同的范围内声明 不同类型的两个变量。
  2. 您不希望在目录上启动线索 搜索,并且不希望在文件上启动另一个 。

项目编号为2的问题是您正在处理多线程的最大瓶颈之一 - 即磁盘IO。通过执行多于1个工作线程来执行磁盘IO(在标准HDD设备上),您将不会获得任何收益。

解释更多关于你想要做什么(请举例)。可能有一个更好的过程。

0

我已编辑帖子(正在等待同行评审)。如果它获得批准,我编辑了代码来修复范围和拼写错误的基本问题,但我不认为你已经准备好了多线程,更不用说生产者 - 消费者队列了(上帝知道我已经涉足多线程,线程一段时间,我仍然结束了我的暗示,但那可能只是我!)。

您应该先适应范围和多线程。特别阅读对于实现成功的多线程解决方案至关重要的锁定机制/并发问题。其次,正如IAbstract所建议的那样,实际上通过互斥/信号来实现多线程来获得多线程性能以及获得期望的生产者 - 消费者队列。

此外,如果您感觉舒适,您还可以使用任务并行库查看最新的Async CTP1 DataFlow库,该库最新支持此模式。或者,您可以使用BlockingCollection来实现这种模式。

Stackoverflow也有问题围绕你的问题,给出了一些优秀的答案。只要搜索“生产者 - 消费者”来阅读它们

1

首先,Directory是一个静态类,所以你将无法一个集合。您需要改用DirectoryInfo。其次,我将使用一个将保存DirectoryInfo实例的队列。这些文件可以作为处理单个文件夹的一部分进行枚举。

下面是我将如何使用生产者 - 消费者模式。该实现使用BlockingCollection类作为阻塞队列的实现。阻塞队列在生产者 - 消费者模式中非常有用,因为它们几乎抽象了所有生产者 - 消费者细节。

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约束部分是广泛的。

1

正如其他海报所示,尝试执行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); 
     } 
    } 
} 
相关问题