有以下功能。
async Task<int> T1() { Console.WriteLine("T1"); return await Task.FromResult(1); }
async Task<string> T2() { Console.WriteLine("T2"); return await Task.FromResult("T2"); }
async Task<char> T3() { await Task.Delay(2000); Console.WriteLine("T3"); return await Task.FromResult('A'); }
async Task<string> T4() { Console.WriteLine("T4"); return await Task.FromResult("T4"); }
// U1, U2, U3, and U4 need to be run right after T1, T2, T3, and T4 respectively
void U1() { System.Threading.Thread.Sleep(1000); Console.WriteLine($"After T1"); }
void U2() { System.Threading.Thread.Sleep(4000); Console.WriteLine($"After T2"); }
void U3() { System.Threading.Thread.Sleep(1000); Console.WriteLine($"After T3"); }
void U4() { System.Threading.Thread.Sleep(1000); Console.WriteLine($"After T4"); }
// TAll() needs to be run as soon as T1, T2, T3, and T4 finished.
void TAll() { Console.WriteLine("To be run after T1, T2, T3, T4"); }
// All() runs after all functions are done.
void All() { Console.WriteLine("To be run after U1, U2, U3, U4"); }
但是,以下呼叫
var t1 = T1().ContinueWith(_ => U1());
var t2 = T2().ContinueWith(_ => U2());
var t3 = T3().ContinueWith(_ => U3());
var t4 = T4().ContinueWith(_ => U4());
await Task.WhenAll(t1, t2, t3, t4);
TAll();
All();
返回
T1 T2 T4 After T1 After T4 T3 After T3 After T2 To be run after T1, T2, T3, T4 To be run after U1, U2, U3, U4
预期输出顺序为
T1 T2 T4 After T1 After T4 T3 To be run after T1, T2, T3, T4 After T3 After T2 To be run after U1, U2, U3, U4
答案 0 :(得分:4)
您应该use async
and await
rather than ContinueWith
。就您而言,添加新的async
方法将简化代码:
var t1 = T1();
var u1 = InvokeU1(t1);
var t2 = T2();
var u2 = InvokeU2(t2);
var t3 = T3();
var u3 = InvokeU3(t3);
var t4 = T4();
var u4 = InvokeU4(t4);
await Task.WhenAll(t1, t2, t3, t4);
TAll();
await Task.WhenAll(u1, u2, u3, u4);
All();
async Task InvokeU1(Task task) { await task; U1(); }
async Task InvokeU2(Task task) { await task; U2(); }
async Task InvokeU3(Task task) { await task; U3(); }
async Task InvokeU4(Task task) { await task; U4(); }
答案 1 :(得分:3)
任务的继续实际上是任务。在您的示例中,您正在等待继续,因此在完成所有目标任务及其所有继续时,将记录“要在...之后运行” 。
考虑一下:
//target tasks
var t1 = T1();
var t2 = T2();
var t3 = T3();
var t4 = T4();
//continuations
var c1 = t1.ContinueWith(_ => U1());
var c2 = t2.ContinueWith(_ => U2());
var c3 = t3.ContinueWith(_ => U3());
var c4 = t4.ContinueWith(_ => U4());
await Task.WhenAll(t1, t2, t3, t4);
TAll();
await Task.WhenAll(c1, c2, c3, c4);
All();
输出将符合您的期望。
更新
Stephen添加了一个有关ContinueWith
的很好的技巧,我鼓励您使用它。但是,无论ContinueWith
多么危险,我都试图从概念上解释问题。
答案 2 :(得分:0)
由于您拥有await Task.WhenAll(t1, t2, t3, t4);
,因此可确保T1(),T2(),T3(),T4()及其关联的U1(),U2(),U3(),U4()(顺序取决于在每个线程中提到的sleep或task.deley线程)在继续执行序列中的TALL()和ALL()之前完成。因此,下面的两个语句是最后要打印的
To be run after T1, T2, T3, T4
To be run after U1, U2, U3, U4