Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 限制并发生成和等待工作进程_C#_Task Parallel Library - Fatal编程技术网

C# 限制并发生成和等待工作进程

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()); 但我担心的是,每个并行工作线程只

我有一个C#程序,它将一组工作项排队。对于每个工作项,我生成另一个应用程序(我无法更改)来处理该项。这个过程相对CPU密集。我想限制此应用程序的实例数

我考虑过使用PLINQ:

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个)