Task.WaitAll冻结应用程序C#
我想尝试Threading.Task(C#)并行运行一些工作。 在这个简单的例子中,我有一个带进度条和按钮的表单。 单击时,将调用RunParallel函数。 没有Task.WaitAll()它似乎运行良好。 但是,使用WaitAll语句,表单显示并且没有任何反应。 我不明白我在下面的设置中做错了什么。 提前致谢。
public partial class MainWindow : Form { public delegate void BarDelegate(); public MainWindow() { InitializeComponent(); } private void button_Click(object sender, EventArgs e) { RunParallel(); } private void RunParallel() { int numOfTasks = 8; progressBar1.Maximum = numOfTasks; progressBar1.Minimum = 0; try { List allTasks = new List(); for (int i = 0; i { doWork(i); })); } Task.WaitAll(allTasks.ToArray()); } catch { } } private void doWork(object o1) { // do work... // then this.Invoke(new BarDelegate( UpdateBar )); } private void UpdateBar() { if (progressBar1.Value < progressBar1.Maximum) progressBar1.Value++; } }
您正在等待UI线程。 这会冻结用户界面。 不要那样做。
此外,您正在死锁,因为Invoke
等待UI线程解除阻塞。
我的建议:尽可能使用async/await
。
请不要吞下例外。 你正在以这种方式为自己创造未来的工作。
这就是WaitAll所做的事情,它会阻止所有任务完成。 任务无法完成,因为Invoke将在UI线程上运行其操作,该线程已被WaitAll阻止
要使代码真正异步运行,请尝试以下方法:
private void RunParallel() { int numOfTasks = 8; progressBar1.Maximum = numOfTasks; progressBar1.Minimum = 0; try { var context=TaskScheduler.FromCurrentSynchronizationContext() for (int i = 0; i < numOfTasks; i++) { Task.Factory.StartNew(()=>DoWork(i)) .ContinueWith(()=>UpdateBar(),context); } } catch (Exception exc) { MessageBox.Show(exc.ToString(),"AAAAAARGH"); } } private void DoWork(object o1) { // do work... } private void UpdateBar() { if (progressBar1.Value < progressBar1.Maximum) progressBar1.Value++; }
在这种情况下,每次任务完成时都会在UI上下文中调用UpdateBar而不会导致任何阻塞。
请注意,这不是生产代码,只是一种显示如何异步运行方法并更新UI而不会阻塞的方法。 您需要阅读有关任务的内容,以了解它们的作用以及它们的工作方式。
在.NET 4.5+中使用async/await
,您可以用更简单的方式编写它。 以下将在后台执行DoWork而不会阻塞,但每次任务完成时仍会更新UI。
private async void button1_Click(object sender, EventArgs e) { int numOfTasks = 8; progressBar1.Maximum = numOfTasks; progressBar1.Minimum = 0; try { for (int i = 0; i < numOfTasks; i++) { await Task.Run(() => DoWork(i)); UpdateBar(); } } catch (Exception exc) { MessageBox.Show(exc.ToString(), "AAAAAARGH"); } }
await
告诉编译器在右边的任务完成时生成代码以在原始(UI)线程上执行其下面的任何内容:
在doWork中,您调用this.Invoke(...)
等待UI线程处理消息。 不幸的是,你的UI线程没有处理消息,因为它正在等待所有的doWork(...)
完成。
最简单的修复是更改this.Invoke
to this.BeginInvoke
(它将发送消息但不等待它们被处理)在doWork中。 虽然,我必须管理它仍然不是书本,因为UI不应该等待任何事情。 简单模式(预异步/等待时代):
Task.Factory.StartNew(() => { ... work ... }) .ContinueWith((t) => { ... updating UI (if needed) ... }, TaskScheduler.FromCurrentSynchronizationContext());
RunParallel
阻塞,直到完成所有任务。 使用不同的机制来通知UI。
上述就是C#学习教程:Task.WaitAll冻结应用程序C#分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注---计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/962491.html