【问题标题】:Wait for Parallel Programming to Finish all tasks without freezing up GUI等待并行编程完成所有任务而不冻结 GUI
【发布时间】:2017-05-23 22:27:10
【问题描述】:

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

  1. 如何等待我的所有任务完成运行而不冻结我的主窗体。
  2. 我解决以下问题的方法是最好的方法吗?

我有一个 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(); 在我的任务完成之前运行。

在不冻结 Windows 窗体的情况下,运行所有 RunTask 任务并在完成后运行 RunOnCompletionOfTasks 的最有效方法是什么?

请,谢谢。

【问题讨论】:

  • 我想你在找await Task.WhenAll

标签: c# .net multithreading parallel-processing


【解决方案1】:

如果您需要执行多个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 限制),您可以尝试在简单的 Task 内执行 Parallel.ForEach

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

【讨论】:

  • 谢谢。 Task.WhenAll 似乎确实非常有效。但是,我仍然遇到任务运行时 GUI 冻结的问题。知道如何克服这个问题吗?
  • 您是否在 private async void button_click 处理程序中等待这些任务?如果是,你应该确保你的任务没有做 CPU 工作。如果他们这样做了,他们就没有有效地运行异步,你应该依赖第二个选项。
  • 把整个函数放在你的答案中。例如 private async void clickHandler。如果你这样做,那么它是解决他问题的完美解决方案。
【解决方案2】:

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

  1. 当你需要用 IO 做一些事情时,通常是异步播放。

  2. 当您需要进行计算时(例如归档文件) 或图像处理)通常是并行的东西。

async await 模式只是一个捷径,它不是灵丹妙药。

如果您只需要并行计算,我建议您使用来自 TPL 的并行人员,例如 ParallelForEach,它们很酷且经过优化,可以很好地获得最佳性能。

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

你的处理器不能做更多的事情

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

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

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

附言 在 UI 中使用 ContinueWith。 TPT 中的任何内容都将返回具有此方法的任务, 更新 UI 确保您当前所在的线程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-10
    • 2020-12-03
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多