Parallel.Foreach使用Invoke开始空闲

时间:2017-11-30 16:06:39

标签: c# .net winforms parallel-processing parallel.foreach

我遇到Parallel.Foreach循环问题。只要我不调用一个方法来增加父GUI程序的Progressbar值,它就可以正常工作。 其中KeinPapierVersand是一个简单的List<int>对象,EinzelnachweisDruckDatumDateTime

Parallel.ForEach(KeinPapierVersand, partner =>
{
    generate_PCL_nachweis(partner, EinzelnachweisDruckDatum, true, false);
    generate_BGF_Report(partner, EinzelnachweisDruckDatum, false);

    //If the following line is uncommented, the loop starts to idle after about 200 
    // processed Items and will never reach the code after the loop.

    myProgressbar_einzelnachweis_druck.Parent.BeginInvoke(new MethodInvoker(delegate 
    { 
        myProgressbar_einzelnachweis_druck.Value = 
                                         myProgressbar_einzelnachweis_druck.Value + 1; 
    }));
});

这是我在C#中实现并行性的第一步。我不知道这里有什么问题,没有抛出异常(以前在Try / Catch中有过)。 如果没有调用进度条,循环结束总是没有问题。 为什么我的逻辑不起作用?我在推理中的错误在哪里?请帮忙。

编辑: 这里的问题是一个僵局,Aaron在下面完美地解释了这个问题。 我把我想要处理的整个工作量放到后台工作中。这完美无瑕。

1 个答案:

答案 0 :(得分:3)

最有可能的是,您从主UI线程调用Parallel.ForEach方法。比如,响应按钮点击或其他UI事件。假设是这种情况,那么Parallel.ForEach行本身就在主UI线程上运行,并将阻止该主线程等待,直到它所请求的所有并发工作完成。

Invoke()的工作方式是它向主UI线程发送消息并等待消息得到处理。该处理完成后,将返回并继续进行。在你的代码中,当一个线程调用Invoke()时,它将在那里等待Invoke完成。但是,Invoke永远不会完成,因为主线程被Parallel.ForEach阻塞,并且无法处理更新进度条的请求,直到Parallel.ForEach完成。这是一种僵局。

有很多方法可以解决这个问题。它们基本上都等于将Parallel.ForEach从主线程中移除。最简单的方法之一,如果你可以在这里(没有足够的代码示例告诉)是使用async / await来启动任务,然后调用Parallel.ForEach并等待结果。这将释放您的主线程,以便能够处理进度条更新。

一旦你开始工作,你可能还想考虑切换到在这里使用BeginInvoke而不是Invoke,因为BeginInvoke不会在完成之前等待主线程处理消息。使用起来有点棘手,因为无法保证更新顺序,甚至在ForEach完成后也可能发生更新。它不会解决您的根问题,您必须先修复它,但它会更有效,因为Invoke()版本实际上会降低您的并行循环速度。