如何递归搜索文件夹&使用生产者/消费者队列的文件?

时间:2011-06-09 16:52:25

标签: c# multithreading producer-consumer

我想首先搜索目录,然后搜索其中的文件,搜索关键字。

我知道我需要两个班级,Producer class&消费者类,但我不知道如何使用c#producer / consumer queue进行搜索?

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();
    }
}

4 个答案:

答案 0 :(得分:1)

最初的问题:

  1. 您要声明2个变量 使用相同的不同类型 变量名具有相同的范围。
  2. 您不想启动线程 搜索目录和另一个 一个在档案上。
  3. 项目编号2的问题在于您正在解决多线程的最大瓶颈之一 - 即磁盘IO。通过实现多个工作线程,执行磁盘IO(在标准HDD设备上)将无法获得任何好处。

    详细说明你想做什么(请举个例子)。可能有一个更好的过程。

答案 1 :(得分:1)

首先,Directory是一个静态类,因此您将无法使用一个集合。您需要使用DirectoryInfo代替。其次,我会使用一个包含DirectoryInfo个实例的队列。然后可以将这些文件枚举为处理单个文件夹的一部分。

以下是使用producer-consumer模式的方法。此实现使用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绑定部分很广泛。

答案 2 :(得分:1)

正如其他海报所说,尝试执行IO的多个线程会导致问题。但是,它们可以用于构造完整的direcotries队列(如果它非常深),然后是一个单独的线程来对文件进行正则表达式。有点像这样:

    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);
        }
    }
}

答案 3 :(得分:0)

我编辑了帖子(等待同行评审)。如果它确实获得批准,我已经编辑了代码来修复范围和拼写错误的基本问题,但我不认为你已经准备好进行多线程,更不用说生产者 - 消费者队列了(天知道我已涉足多个 - 穿线一段时间,我仍然最终弄乱了我的意见,但那可能只是我!)。

首先应该熟悉范围和多线程。特别是读取锁定机制/并发问题,这些问题对于实现成功的多线程解决方案至关重要。

其次,正如IAbstract建议的那样,确实使用互斥锁/信号量实现多个线程,以获得多线程的性能以及获得所需的生产者 - 消费者队列。

另外,如果您感觉舒服,还可以使用Tasks Parallel Library查看最新的Async CTP1 DataFlow库,该库最新支持此模式。或者,您可以使用BlockingCollection来实现此模式。

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