Task.WaitAll()无法按预期工作

我正在试图弄清楚如何使用Task类。 在过去我总是使用常规的Thread类,但我正在尝试掌握所有的异步编程……

作为一个例子,我创建了一个包含所有代码的主Winforms应用程序。 我的问题的相关代码是:

//Relevant delegates public delegate void MethodAction(int num); public delegate void MethodConversion(); public delegate void OnCompletionAction(string completiontext); //Button user presses private void button4_Click(object sender, EventArgs e) { richTextBox1.Clear(); sw.Reset(); sw.Start(); Sync.RunAsync3(calcSim); } //The method that simulates a calculation by adding a sleep //the input param threadlength is just to allow threads to take longer than others //since I'm multithreading, I have to invoke the writing code on the windows RichTextbox control private void calcSim(int threadlength) { string threadname = Thread.CurrentThread.Name; for (int i = 0; i  { richTextBox1.AppendText(string.Format("Thread: {0}\tVersion: {1}\n", threadname, (i + 1).ToString())); })); } } //Class that contains the different processing methods public static class Sync { public static event OnCompletionAction OnProcCompletion; public static void RunAsync3(MethodAction doM) { Task[] t = new Task[4]; for(int i = 0; i  { doM(50 * i); })); } Task.WaitAll(t); if (OnProcCompletion != null) OnProcCompletion("RunSync method finished"); } } 

问题在于Task.WaitAll(t)……由于某些原因,我无法弄清楚,它完全阻塞了该行并且不再响应。 如果省略该行,表单将实时更新,执行大约需要3秒。

我的问题是:为什么在释放它并允许其余代码执行之前,Task.WaitAll()阻止UI线程3秒钟?

我知道它应该阻止UI一段时间(直到计算所有线程),但它会无休止地阻止完整的应用程序。 它似乎永远等待?

编辑

我被建议使用WhenAll而不是WaitAll。 我已经重写了RunAsync3,如下所示:

 public static void RunAsync3(MethodAction doM) { Task[] t = new Task[4]; for(int i = 0; i  { doM(50 * i); })); } //Task.WaitAll(t); -> deadlock Task.WaitAll(new Task [] { Task.WhenAll(t) }); if (OnProcCompletion != null) OnProcCompletion("RunSync method finished"); } 

但这仍然陷入僵局……? 我可能错误地使用了WhenAll?

编辑2

因为每个人都声称我阻止了UI线程,所以我决定尝试另一种方式:通过在UI线程中运行一个新线程作为我的调用线程(这样就可以在我的线程而不是UI线程上发生阻塞)。 这有效,但显然不是最好的方法!

 private void button4_Click(object sender, EventArgs e) { Thread t = new Thread(new ThreadStart(() => { richTextBox1.Invoke((MethodConversion)(() => richTextBox1.Clear())); sw.Reset(); sw.Start(); Sync.RunAsync3(calcSim); })); t.Start(); } public static void RunAsync3(MethodAction doM) { Task[] t = new Task[4]; for(int i = 0; i  { doM(50 * i); })); } Task.WaitAll(t); //Task.WaitAll(new Task [] { Task.WhenAll(t) }); if (OnProcCompletion != null) OnProcCompletion("RunSync method finished"); } 

你造成了僵局。

UI线程正在等待完成4个任务。

另一方面,运行calcSim那4个任务试图在UI线程上调用代码 – >死锁。

您应该使用Task.WhenAll()代替。 该方法将返回一个新任务,当您完成所有for任务时,该任务将标记为已完成。 如果您等待该任务,您的UI线程将被释放,因此calcSim将能够调用UI线程上的代码,从而避免死锁。

更新

你错了。 你还在使用WaitAll ,这是一个阻塞调用。 你应该用WhenAll 替换它。

 await Task.WhenAll(t); 

从文档 :

创建一个任务,该任务将在所有提供的任务完成后完成。

通过在结果上调用await ,您的UI线程将是免费的 – 直到所有4个任务完成。 发生这种情况时, RunAsync3方法将恢复。

Task.WaitAll阻塞并等待所有任务完成,并在UI线程上调用它。

你的所有任务都试图调用richTextBox1.Invoke (在UI线程中)但你的UI线程在Task.WaitAll被阻止。 僵局。

因为它等待你的线程结束。 他们运行3秒300X10