我认为这是一个非常常见的线程处理场景:
如果假设每个作业在他完成时都会触发一个事件(我正在使用BackgroundWorker类),我可以想出几种方法来完成这个任务,但我不知道什么是“正确”的解决方案。我希望你们中的一些专家能为我指明正确的方向。
解决方案1:在Main()函数中有一个while(继续){ Threading.Sleep(1000);}循环。Job_Completed事件处理程序中的代码将设置= false,当A)没有待排队的作业时,B)将所有排队的作业都完成。我以前使用过这个解决方案,虽然它似乎有效,但fine...it对我来说似乎有点“奇怪”。
解决方案2:在Main()函数中使用Application.Run()。类似地,Job_Completed事件处理程序中的代码将调用Application.Exit(),当A)不需要排队,而B)所有排队作业已经完成时。
解决方案3:使用ThreadPool,将所有500-1000个请求排队,让它们一次运行10个请求(SetMaxThreads),然后以某种方式等待它们全部完成。
在所有这些解决方案中,基本思想是,每次完成另一个作业时,都会启动一个新的作业,直到没有剩下的作业为止。因此,问题不仅在于等待现有作业的完成,还在于等待到不再有任何待处理的作业开始。如果ThreadPool是正确的解决方案,那么等待ThreadPool完成所有排队项目的正确方法是什么?
我认为我在这里的最大困惑是,我不太明白事件是如何从我的Main()函数中触发的。很明显,他们是这样做的,我只是不明白从Windows消息循环的角度来看它的机制。解决这个问题的正确方法是什么?为什么?
发布于 2009-04-28 02:56:19
即使其他的答案很好,如果你想要另一个选择(你永远没有足够的选择),那么这作为一个想法怎么样?
只需将每个作业的数据放入FIFO堆栈中的结构中即可。
创建15个线程。
每个线程将从堆栈中获得下一个作业,并将其弹出。
当线程完成处理时,获得下一个作业,如果堆栈为空,则线程将死或只是休眠,等待。
唯一的复杂性,这是相当简单的解决,是让弹出在一个关键的部分(同步读取/pop)。
发布于 2009-04-28 01:09:52
Re:“不知何故,等待他们全部完成”
ManualResetEvent是您的朋友,在开始您的大批处理之前,创建这些小狗之一,在您的主线程中等待它,在工作完成后将其设置在后台操作的末尾。
另一个选项是手动创建线程并执行foreach线程thread.Join()
你可以用这个(我在测试期间用这个)
private void Repeat(int times, int asyncThreads, Action action, Action done) {
if (asyncThreads > 0) {
var threads = new List<Thread>();
for (int i = 0; i < asyncThreads; i++) {
int iterations = times / asyncThreads;
if (i == 0) {
iterations += times % asyncThreads;
}
Thread thread = new Thread(new ThreadStart(() => Repeat(iterations, 0, action, null)));
thread.Start();
threads.Add(thread);
}
foreach (var thread in threads) {
thread.Join();
}
} else {
for (int i = 0; i < times; i++) {
action();
}
}
if (done != null) {
done();
}
}用法:
// Do something 100 times in 15 background threads, wait for them all to finish.
Repeat(100, 15, DoSomething, null)发布于 2009-04-28 01:09:58
我只想使用任务并行库。
您可以使用您的任务作为一个简单的Parallel.For循环来完成这一任务,并且它将自动非常干净地管理这一过程。如果您不能等待C# 4和微软的实现,一个临时的解决办法就是编译和使用TPL的单点实现。(我个人更喜欢MS实现,尤其是较新的beta版本,但Mono在今天是功能性的和可再发行的。)
https://stackoverflow.com/questions/795842
复制相似问题