简体   繁体   English

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

[英]Wait for Parallel Programming to Finish all tasks without freezing up GUI

I'm new to all the parallel programming paradigms in .NET and I'd like to know two things: 我是.NET中所有并行编程范例的新手,我想知道两件事:

  1. How can I wait for all of my tasks to finish running without it freezing up my main form. 我如何等待我的所有任务完成运行而又不冻结我的主要表单。
  2. Is my method of solving the following problem the best way to go about doing it? 我解决以下问题的方法是否是解决此问题的最佳方法?

I have a private async Task RunTask(string task) method that I need to run as many times as the number of tasks I have. 我有一个private async Task RunTask(string task)方法,该方法需要运行的次数与我拥有的任务数一样多。

Inside a private async void button_click(object sender, EventArgs e) class, I have a List of strings called tasklist which initializes the tasks I need to run. 在一个private async void button_click(object sender, EventArgs e)类中,我有一个名为tasklist的字符串列表,该字符串列表初始化了我需要运行的任务。 I'm running the following code: 我正在运行以下代码:

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

I need to be able to utilize all my CPU cores and run all tasks in the shortest amount of time possible. 我需要能够利用我所有的CPU内核,并在尽可能短的时间内运行所有任务。 I figured Parallel.ForEach was the best way to achieve this but my tasks are also async because they have functions that require waiting on other methods. 我认为Parallel.ForEach是实现此目标的最佳方法,但我的任务也是async因为它们的功能需要等待其他方法。 My tasks also append one string to a List<string> object within the class during their execution. 我的任务在执行期间还将一个字符串附加到类中的List<string>对象上。

Parallel.ForEach causes my Windows Form to freeze up so I encapsulated it within a thread. Parallel.ForEach导致Windows窗体冻结,因此我将其封装在线程中。 The problem with this is that RunOnComlpetionOfTasks(); 问题是RunOnComlpetionOfTasks(); runs before my tasks have completed. 在我的任务完成之前运行。

What's the most efficient way for me to run all my RunTask tasks and then run RunOnCompletionOfTasks upon completion without freezing up the Windows Form? 什么是最有效的办法,我跑我所有的RunTask任务,然后运行RunOnCompletionOfTasks完成后,不会冻结了Windows窗体?

Please and thank you. 谢谢,麻烦您了。

If you need to execute multiple Tasks (which are awaitable) then Parallel.ForEach may not be the best choice. 如果您需要执行多个Tasks (可以等待),那么Parallel.ForEach可能不是最佳选择。 It is truly designed for CPU bound processes and does not support async operations. 它是专为CPU绑定进程而设计的,不支持async操作。

You may try to rewrite your code using Task.WhenAll() : 您可以尝试使用Task.WhenAll()重写代码:

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

This way your are leveraging the use of async / await pattern inside your method call. 这样,您就可以在方法调用中利用async / await模式。

If, instead, you realize that your tasks are not properly async (and are only CPU bound) you may try to execute Parallel.ForEach inside a simple Task 相反,如果您意识到自己的任务未正确async (并且仅与CPU绑定),则可以尝试在一个简单的Task执行Parallel.ForEach

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

First off all you need to distinguish parallel and asynchronous: 首先,您需要区分并行和异步:

  1. When you need to do something with IO asynchronous is usually play. 当您需要使用IO进行某些操作时,通常会玩。

  2. When you need to do something with computing (like archiving files or image processing) is parallel stuff is usually coming play. 当您需要对计算进行某些处理(例如存档文件或图像处理)时,通常会出现并行操作。

async await pattern its just a shortcut and its not silver bullet. 异步等待模式只是一个快捷方式,而不是灵丹妙药。

If You need just to parallel your computation I suggest to use parallel staff from TPL like ParallelForEach, they a playing cool and optimized very good to get maximum performance. 如果您只需要并行计算,我建议使用TPL的并行人员(例如ParallelForEach),它们玩起来很酷,而且经过优化,非常好,以实现最高性能。

If you are trying to perform some IO operations this can make sense but on more or less huge processing data amount - like server app. 如果您尝试执行一些IO操作,这可能是有道理的,但处理的数据量或多或少-如服务器应用程序。

Your processor can't do more then it can 您的处理器不能做的那么多

Any parallel staff sill not help you if your task is not parallel. 如果您的任务不是并行的,那么任何并行人员都无法为您提供帮助。 Be aware of any context switch has some cost. 请注意,任何上下文切换都有一定的成本。 TaskSheduler will use queue to decrease threads count but its doing some work again. TaskSheduler将使用队列来减少线程数,但它又做了一些工作。

Thread new Thread is evil (here at least). 线程新线程是邪恶的(至少在这里)。 Your processor will be switched to one more thread more frequently (more threads - more switches) 您的处理器将更频繁地切换到一个线程(更多线程-更多开关)

Finally: Try not yo use TPL things when you are not aware how does things work. 最后:当您不知道TPL的工作原理时,请不要使用它们。 Just use classes you need and dont do optimization that dont really optimize. 只需使用您需要的类,就不要进行没有真正优化的优化。

PS Use ContinueWith in UI. PS在UI中使用ContinueWith。 Anything in TPT will return task that has this method, Updating UI be sure of thread you are currently in. TPT中的任何内容都将返回具有此方法的任务,更新UI时请确保当前使用线程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM