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



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

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

请,谢谢。

如果您需要执行多个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`

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

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

  2. 当您需要对计算执行某些操作(例如存档文件)时 或图像处理)是并行的东西通常正在发挥作用。

异步等待模式只是一个快捷方式,而不是银弹。

如果你只需要并行你的计算,我建议使用来自TPL的并行工作人员,如ParallelForEach,他们玩得很酷,优化非常好,以获得最大的性能。

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

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

如果您的任务不并行,任何平行的职员门槛都无济于事。 请注意,任何上下文切换都有一定的成本。 TaskSheduler将使用队列来减少线程计数,但它会再次执行一些工作。

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

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

PS在 UI 中使用继续。TPT 中的任何内容都将返回具有此方法的任务, 更新 UI 时,请确保当前所在的线程。

最新更新