C# 如何知道我所有的生产者-消费者工作何时结束
我有一个Winforms应用程序,它可以读取多个网络文件夹并搜索此文件夹中的文件,此函数用于接收列表文件夹: 现在,在搜索过程中,我的UI被锁定以防止不必要的点击,我想知道我的所有文件夹何时完成搜索以解锁。C# 如何知道我所有的生产者-消费者工作何时结束,c#,.net,multithreading,producer-consumer,C#,.net,Multithreading,Producer Consumer,我有一个Winforms应用程序,它可以读取多个网络文件夹并搜索此文件夹中的文件,此函数用于接收列表文件夹: 现在,在搜索过程中,我的UI被锁定以防止不必要的点击,我想知道我的所有文件夹何时完成搜索以解锁。 但我的问题是,我正在搜索多个文件夹。事件AllFilesProcessedEventHandler触发了几次,我想知道我的所有搜索何时完成。下面是QuickIO.Net的递归示例 using System; using System.Collections.Concurrent; using
但我的问题是,我正在搜索多个文件夹。事件AllFilesProcessedEventHandler触发了几次,我想知道我的所有搜索何时完成。下面是QuickIO.Net的递归示例
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
using SchwabenCode.QuickIO;
namespace ConsoleApplication3
{
internal class Program
{
private static readonly BlockingCollection<QuickIOFileInfo> fileInfos = new BlockingCollection<QuickIOFileInfo>();
private static void Main(string[] args)
{
var task = Task.Factory.StartNew(() =>
{
Int32 totalSize = 0;
Parallel.ForEach(fileInfos.GetConsumingEnumerable(), fi =>
{
Interlocked.Add(ref totalSize, (int)fi.Bytes);
});
Console.WriteLine("All docs bytes amount to {0}", totalSize);
});
ProcessDirectory("C:\\");
fileInfos.CompleteAdding();
Task.WaitAll(task);
}
private static void ProcessDirectory(string path)
{
Parallel.ForEach(QuickIODirectory.EnumerateDirectories(path), dir =>
{
try
{
Parallel.ForEach(QuickIODirectory.EnumerateFiles(dir), file =>
{
if (file.AsFileInfo().Extension.Equals(".docx"))
fileInfos.Add(file);
});
ProcessDirectory(dir.FullName);
}
catch (Exception e)
{
Console.WriteLine("Unable to access directory {0}", dir.FullName);
}
});
}
}
}
当所有元素都被添加时,阻塞集合将通过调用CompleteAdding自动向Parallel ForEach发送信号
扫描256GB SSD(剩余74GB)和总共738k+文件需要16.8秒。您使用的是哪个版本的.NET?4.5还是更早?有没有理由使用一个队列?为什么不把一个文件夹作为一个参数传递给函数,这样你就可以避免这个锁?你能做到吗?我不想停止使用我的锁。如果我在中间按下启动,我的应用程序仍然在添加文件。结果可能是我的应用程序会错误地看我。回答。你看到你不能做的事情了吗?为什么要使用联锁。添加?一个简单的Map-Reduce看起来更有效,而且无阻塞。唯一的原因是联锁。添加是如果你想检查运行计数。即使这样,也有可能使你的地图批量减少稍微困难一点,但确实可行。没错,但样本绝不是生产质量代码。这只是为了演示如何在不从头开始重新设计阻塞集合的情况下继续进行他的挑战..AsParallel.Sumfi=>intfi。Bytes@Aron谢谢你的评论。我怀疑用户3637066不仅仅是想计算文件大小的总和。什么是QuickIOFileInfo?
public class ProducerConsumer
{
public delegate void OnFileAddDelegate(PcapFileDetails pcapFileDetails);
public event OnFileAddDelegate OnFileAddEventHandler;
public delegate void AllFilesProcessedDelegate();
public event AllFilesProcessedDelegate AllFilesProcessedEventHandler;
private readonly Queue<string> _queue;
private int counter;
public ProducerConsumer(int workerCount, IEnumerable<string> list)
{
_isSearchFinished = true;
_queue = new Queue<string>(list); // fill the queue
counter = _queue.Count; // set up counter
for (int i = 0; i < workerCount; i++)
Task.Factory.StartNew(Consumer);
}
private void Consumer()
{
FileChecker fileChecker = new FileChecker();
for (; ; )
{
string file;
lock (_queue)
{
// synchronize on the queue
if (_queue.Count == 0) return; // we are done
file = _queue.Dequeue(); // get file name to process
} // release the lock to allow other consumers to access the queue
// do the job
string result = fileChecker.Check(file); // Check my file
if (OnFileAddEventHandler != null && result ) // In case my file OK, fired up event to my main UI
OnFileAddEventHandler(file);
// decrement the counter
if (Interlocked.Decrement(ref counter) != 0)
continue; // not the last
// all done - we were the last
if (AllFilesProcessedEventHandler != null)
AllFilesProcessedEventHandler();
return;
}
}
}
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
using SchwabenCode.QuickIO;
namespace ConsoleApplication3
{
internal class Program
{
private static readonly BlockingCollection<QuickIOFileInfo> fileInfos = new BlockingCollection<QuickIOFileInfo>();
private static void Main(string[] args)
{
var task = Task.Factory.StartNew(() =>
{
Int32 totalSize = 0;
Parallel.ForEach(fileInfos.GetConsumingEnumerable(), fi =>
{
Interlocked.Add(ref totalSize, (int)fi.Bytes);
});
Console.WriteLine("All docs bytes amount to {0}", totalSize);
});
ProcessDirectory("C:\\");
fileInfos.CompleteAdding();
Task.WaitAll(task);
}
private static void ProcessDirectory(string path)
{
Parallel.ForEach(QuickIODirectory.EnumerateDirectories(path), dir =>
{
try
{
Parallel.ForEach(QuickIODirectory.EnumerateFiles(dir), file =>
{
if (file.AsFileInfo().Extension.Equals(".docx"))
fileInfos.Add(file);
});
ProcessDirectory(dir.FullName);
}
catch (Exception e)
{
Console.WriteLine("Unable to access directory {0}", dir.FullName);
}
});
}
}
}