使用Timer测量Parallel.ForEach进度意外暂停

时间:2015-01-31 03:43:03

标签: c# winforms timer parallel.foreach

我第一次使用Parallel.ForEach,我正在处理文件;在WinForms应用程序的上下文中。

根据其他线程对此编码问题的指导(Parallel.ForEach进度报告)我的类上有一个public(int)计数器属性,它包含并行代码,并且它已成功更新;我的表格上还有一个定时读取计数器的计时器。

问题在于,当我执行并行代码时,可见进度更新似乎停止,然后在并行代码完成后立即启动。

仅供参考 - 我直接调用并行代码 - 也就是说,不是通过后台工作程序或异步方法。

2 个答案:

答案 0 :(得分:4)

Parallel.ForEach实际上以并行方式评估查询,但确实等待执行完成并阻塞调用线程。

您应该在单独的线程/后台工作/任务上使用它来更新进度变量,同时不阻止UI。

答案 1 :(得分:1)

如果从UI线程调用Parallel.ForEach()(缺少代码示例,我们无法确切知道发生了什么),那么该方法停止并等待所有处理完成的事实将阻止您的UI线程执行任何其他工作,包括a)允许处理计时器事件,以及b)即使处理完计时器也允许更新UI。

一种可能的方法是将Parallel.ForEach()的电话打包到Task.Run()。例如:

private async void button1_Click(object sender, EventArgs e)
{
    // some stuff

    await Task.Run(() => Parallel.ForEach(...));

    // some other stuff
}

或者,您可以将整个事务作为单独的任务执行:

private async void button1_Click(object sender, EventArgs e)
{
    // some stuff

    List<Task> tasks = new List<Task>();

    foreach (...)
    {
        tasks.Add(Task.Run(() => ...));
    }

    await Task.WhenAll(tasks);

    // some other stuff
}

(上面的例子省略了具体细节,因为在问题中没有代码示例,就无法知道实际会发生什么)。

任何一种方法都应该释放你的UI线程,以便在处理过程中处理进度更新。