我想首先搜索目录,然后搜索其中的文件,搜索关键字。
我知道我需要两个班级,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();
}
}
答案 0 :(得分:1)
最初的问题:
项目编号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也有一些围绕你的问题的问题,给出了一些很好的答案。只需搜索“生产者 - 消费者”来阅读它们