我是 .NET 中所有并行编程范例的新手,我想知道两件事:
我- 怎么能等待我的所有任务完成运行而不冻结我的主窗体。
- 我解决以下问题的方法是否是最好的方法?
我有一个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`
首先,您需要区分并行和异步:
-
当你需要用IO异步做一些事情时,通常是播放。
-
当您需要对计算执行某些操作(例如存档文件)时 或图像处理)是并行的东西通常正在发挥作用。
异步等待模式只是一个快捷方式,而不是银弹。
如果你只需要并行你的计算,我建议使用来自TPL的并行工作人员,如ParallelForEach,他们玩得很酷,优化非常好,以获得最大的性能。
如果您尝试执行一些 IO 操作,这可能是有意义的,但或多或少处理数据量巨大 - 如服务器应用程序。
您的处理器无法执行更多操作
如果您的任务不并行,任何平行的职员门槛都无济于事。 请注意,任何上下文切换都有一定的成本。 TaskSheduler将使用队列来减少线程计数,但它会再次执行一些工作。
线程新线程是邪恶的(至少在这里)。您的处理器将更频繁地切换到一个线程(更多线程 - 更多开关)
最后:当你不知道事情是如何工作的时,尽量不要使用TPL的东西。只使用你需要的类,不要做没有真正优化的优化。
PS在 UI 中使用继续。TPT 中的任何内容都将返回具有此方法的任务, 更新 UI 时,请确保当前所在的线程。