C# 限制并发生成和等待工作进程
我有一个C#程序,它将一组工作项排队。对于每个工作项,我生成另一个应用程序(我无法更改)来处理该项。这个过程相对CPU密集。我想限制此应用程序的实例数 我考虑过使用PLINQ:C# 限制并发生成和等待工作进程,c#,task-parallel-library,C#,Task Parallel Library,我有一个C#程序,它将一组工作项排队。对于每个工作项,我生成另一个应用程序(我无法更改)来处理该项。这个过程相对CPU密集。我想限制此应用程序的实例数 我考虑过使用PLINQ: Parallel.ForEach( workItems, new ParallelOptions { MaxDegreeOfParallelism = 4 }, x => Process.Start("worker", x).WaitForExit()); 但我担心的是,每个并行工作线程只
Parallel.ForEach(
workItems,
new ParallelOptions { MaxDegreeOfParallelism = 4 },
x => Process.Start("worker", x).WaitForExit());
但我担心的是,每个并行工作线程只会占用一个线程来等待相应的进程
我还看到PLINQ尝试对返回的项目进行批处理,这意味着它可能会在等待适当大小的批处理时暂停。那么,使用BlockingCollection
的单一生产者/多消费者模式是否可行?问题是每个并行工作线程有一个线程,这比PLINQ解决方案更糟糕
考虑到上述内容已简化,并且我实际上有一个连接到每个工作进程的
TaskCompletionSource
(通过退出的事件),我是否可以使用TPL中的某些内容来执行此操作而不阻塞任何后台线程?如果您可以包装进程
使用进程启动和完成。已退出任务中的事件
:
Task WrapExternalProcess( WorkItem workItem ) { ... }
您可以使用continuations完全删除阻塞。这样做可以:
Task DoAllWork( IEnumerable<WorkItem> workItems )
{
int THREAD_COUNT = 4;
var bag = new ConcurrentBag<WorkItem>( workItems );
var ce = new CountdownEvent( THREAD_COUNT );
var tcs = new TaskCompletionSource<bool>();
for ( int i = 0 ; i < THREAD_COUNT ; i++ ) Work( bag, ce, tcs );
return tcs.Task;
}
void Work(
ConcurrentBag<WorkItem> bag,
CountdownEvent ce,
TaskCompletionSource<bool> tcs
)
{
WorkItem workItem;
if ( bag.TryTake( out workItem) )
{
WrapExternalProcess( workItem )
.ContinueWith( t => Work( bag, ce, tcs ) );
}
else // no more work
{
// If I'm the last thread to finish
if ( ce.Signal() ) tcs.SetResult( true );
}
}
Task-DoAllWork(IEnumerable-workItems)
{
int线程计数=4;
var bag=新的并发包(工作项);
var ce=新的倒计时事件(线程计数);
var tcs=new TaskCompletionSource();
对于(inti=0;i工作(行李、ce、TC));
}
否则我就没有工作了
{
//如果我是最后一个完成的线程
if(ce.Signal())tcs.SetResult(true);
}
}
我实现了如下内容:
var sem = new SemaphoreSlim(4);
foreach (var item in workItems)
{
sem.Wait();
ProcessAsync(item).ContinueWith(_ => sem.Release());
}
这给了我一个单一线程,可以同时运行有限数量的后台进程。TPL中的单个线程是一个问题,这种分析有多糟糕?抱歉:学术练习。实际上,用4个(或8个)线程阻塞实际上不是问题,但我想了解更多关于TPL中的调度和并发选项的信息。是的,我可以使用C#5.0和.NET 4.5。不需要在WaitForExit
上阻塞:我订阅了进程。退出了事件。但为什么需要阻塞这一个线程?你不能在不阻塞任何线程的情况下做同样的事情吗?不知道。我可以吗?这是我最接近不使用任何线程。我必须添加一些其他的东西来跟踪有多少项是未完成的(因为它会在循环中留下N个)