等待并行编程完成所有任务而不冻结GUI

时间:2017-05-23 22:27:10

标签: c# .net multithreading parallel-processing

我是.NET中所有并行编程范例的新手,我想知道两件事:

  1. 如何在不冻结主表单的情况下等待所有任务完成运行。
  2. 解决以下问题的方法是最好的方法吗?
  3. 我有一个private async Task RunTask(string task)方法,我需要运行的次数与我的任务数量相同。

    private async void button_click(object sender, EventArgs e)类中,我有一个名为tasklist的字符串列表,它初始化了我需要运行的任务。我正在运行以下代码:

    Thread thread = new Thread(()=> Parallel.ForEach(tasklist, t => RunTask(t)));
    thread.Start();
    RunOnCompletionOfTasks();
    

    我需要能够利用我所有的CPU内核并在尽可能短的时间内运行所有任务。我认为Parallel.ForEach是实现此目的的最佳方式,但我的任务也是async,因为它们具有需要等待其他方法的功能。我的任务还会在执行期间将一个字符串附加到类中的List<string>对象。

    Parallel.ForEach导致我的Windows窗体冻结,因此我将其封装在一个线程中。这个问题是RunOnComlpetionOfTasks();在我的任务完成之前运行。

    对我来说,运行所有RunTask任务然后在完成时运行RunOnCompletionOfTasks而不冻结Windows窗体的最有效方法是什么?

    请,谢谢你。

2 个答案:

答案 0 :(得分:3)

如果您需要执行多个Tasks(可以等待),那么Parallel.ForEach可能不是最佳选择。它专为CPU绑定流程设计,不支持async操作。

您可以尝试使用Task.WhenAll()重写代码:

var tasks = tasklist.Select(RunTask);
// assuming RunTask is declared as `async Task`
await Task.WhenAll(tasks);

这样您就可以在方法调用中使用async / await模式。

相反,如果您意识到您的任务不正确async(且仅受CPU限制),您可以尝试在简单Parallel.ForEach

内执行Task
await Task.Run(() => Parallel.ForEach(tasklist, RunTask);
// assuming RunTask is not `async Task`

答案 1 :(得分:1)

首先,您需要区分并行和异步:

  1. 当您需要使用IO异步时,通常会播放。

  2. 当您需要对计算执行某些操作时(例如归档文件) 或图像处理)是平行的东西,通常是来玩。

  3. 异步等待模式只是一个捷径,而不是银弹。

    如果您只需要平行计算,我建议使用TPL中的并行工作人员,例如ParallelForEach,它们可以很好地进行优化,并且可以获得最佳性能。

    如果您尝试执行某些IO操作,这可能是有意义的,但或多或​​少处理大量处理数据 - 如服务器应用程序。

    您的处理器无法执行更多操作

    如果您的任务不平行,任何平行的工作人员都无法帮助您。 请注意任何上下文切换都有一些成本。 TaskSheduler将使用队列来减少线程数,但它会再做一些工作。

    线程新线程是邪恶的(至少在这里)。您的处理器将更频繁地切换到另一个线程(更多线程 - 更多交换机)

    <强>最后: 当你不知道事情是如何运作时,尽量不要使用TPL的东西。只需使用您需要的类,不要进行真正优化的优化。

    <强> PS 在UI中使用ContinueWith。 TPT中的任何内容都将返回具有此方法的任务, 更新UI确保您当前所在的主题。