完成线程队列的最佳方法是什么,这样我只能拥有最大数量的线程,如果我已经有那么多线程,代码会在继续之前等待空闲插槽。
我的意思的伪代码示例,我相信这可以用更好的方式完成...
(请检查下面的附加要求)
private int _MaxThreads = 10;
private int _CurrentThreads = 0;
public void main(string[] args)
{
List<object> listWithLotsOfItems = FillWithManyThings();
while(listWithLotsOfItems.Count> 0)
{
// get next item that needs to be worked on
var item = listWithLotsOfItems[0];
listWithLotsOfItems.RemoveAt(0);
// IMPORTANT!, more items can be added as we go.
listWithLotsOfItems.AddRange(AddMoreItemsToBeProcessed());
// wait for free thread slot
while (_CurrentThreads >= _MaxThreads)
Thread.Sleep(100);
Interlocked.Increment(ref _CurrentThreads); // risk of letting more than one thread through here...
Thread t = new Thread(new ParameterizedThreadStart(WorkerThread(item));
t.Start();
}
}
public void WorkerThread(object bigheavyObject)
{
// do heavy work here
Interlocked.Decrement(ref _CurrentThreads);
}
查看了 Sempahore
但它似乎需要在线程内部运行,而不是在创建之前在线程外部运行。在这个例子中,信号量在线程创建后用于暂停它,在我的例子中,在作业完成之前可能有超过 100k 的线程需要运行,所以我宁愿在插槽可用之前不创建线程.
( link to semaphore example )
在实际应用中,数据可以随着程序的进行添加到项目列表中所以 Parallel.ForEach
也不会真正起作用(我是在 SSIS 包中的脚本组件中执行此操作以将数据发送到非常慢的 WCF)。
SSIS 有 .Net 4.0
最佳答案
所以,首先让我说一下,您尝试做的只是在非常具体的安排中对性能进行小幅提升。在线程分配级别尝试和调整可能需要大量工作,因此请确保在继续之前有充分的理由。
现在,首先,如果你想简单地排队工作,你可以把它放在 .NET 线程池上。它只会分配最大配置的线程,任何不适合这些的工作(如果所有线程都忙)将排队等待直到线程可用。
最简单的方法是调用:
Task.Factory.StartNew(() => { /* Your code */});
这将创建一个 TPL 任务并安排它在默认任务调度程序上运行,该调度程序应依次将任务分配给线程池。
如果您需要等待这些任务完成后再继续,您可以将它们添加到一个集合中,然后使用 Task.WaitAll(...)
:
var tasks = new List<Task>();
tasks.Add(Task.Factory.StartNew(() => { /* Your code */}));
// Before leaving the script.
Task.WaitAll(tasks);
但是,如果您需要更深入地控制这些任务的调度,您可以考虑创建一个支持有限并发的自定义任务调度程序。 This MSDN article深入了解它的更多细节并提出可能的实现建议,但这不是一项微不足道的任务。
关于c# - 在继续代码之前等待空闲线程槽,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28413434/