等待一些功能,并在等待任务时继续运行一些代码



有以下功能。

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();

返回

T1T2T4T1之后T4之后T3T3之后T2之后在T1,T2,T3,T4之后运行在U1,U2,U3,U4之后运行

预期的输出顺序为

T1T2T4T1之后T4之后T3在T1,T2,T3,T4之后运行T3之后T2之后在U1,U2,U3,U4之后运行

您应该使用asyncawait而不是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(); }

任务的延续实际上是任务。在您的示例中,您正在等待连续性,因此要在...之后运行..." 将在所有目标任务和所有连续性完成时记录。

考虑一下:

//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();

输出将符合您的期望。

update

Stephen添加了有关ContinueWith的好提示,我鼓励您使用它。但是,无论ContinueWith在这里有多危险,我都试图从概念上解释问题。

由于您有await Task.WhenAll(t1, t2, t3, t4);,因此可以确保T1(),T2(),T3(),T4()及其关联的U1(),U2(),U3(),U4(),U4(),U4()(订单取决于线程睡眠或任务。因此,下面的两个语句是最后一个打印

的语句
To be run after T1, T2, T3, T4
To be run after U1, U2, U3, U4

最新更新