我正在尝试使用C#的async / await / continuewith。
我的目标是必须有两个并行运行的任务,尽管哪个任务按顺序执行一系列操作。
为此,我计划让List<Task>
代表并行运行的2个(或更多)任务,并在每个ContinueWith
上使用Task
我的问题是,当await taskList
已经返回时,似乎没有执行继续回调。
为了总结,这里有一个例子来说明我期待发生的事情:
class Program
{
static public async Task Test()
{
System.Console.WriteLine("Enter Test");
await Task.Delay(100);
System.Console.WriteLine("Leave Test");
}
static void Main(string[] args)
{
Test().ContinueWith(
async (task) =>
{
System.Console.WriteLine("Enter callback");
await Task.Delay(1000);
System.Console.WriteLine("Leave callback");
},
TaskContinuationOptions.AttachedToParent).Wait();
Console.WriteLine("Done with test");
}
}
预期输出为
Enter Test
Leave Test
Enter callback
Leave callback
Done with test
然而,输出是
Enter Test
Leave Test
Enter callback
Done with test
有没有办法让ContinueWith
被调用的任务等待提供的函数在被认为完成之前完成?即。 .Wait将等待两个任务完成,原始任务和ContinueWith返回的任务
答案 0 :(得分:37)
使用ContinueWith
方法链接多个任务时,返回类型将为Task<T>
,而T
是传递给ContinueWith
的委托/方法的返回类型。< / p>
由于异步委托的返回类型为Task
,您最终会得到Task<Task>
并最终等待异步委托返回Task
已完成在第一个await
之后。
要纠正此行为,您需要使用Task
中嵌入的返回Task<Task>
。使用Unwrap
扩展名方法将其解压缩。
答案 1 :(得分:24)
当您进行async
编程时,您应该努力将ContinueWith
替换为await
,因此:
class Program
{
static public async Task Test()
{
System.Console.WriteLine("Enter Test");
await Task.Delay(100);
System.Console.WriteLine("Leave Test");
}
static async Task MainAsync()
{
await Test();
System.Console.WriteLine("Enter callback");
await Task.Delay(1000);
System.Console.WriteLine("Leave callback");
}
static void Main(string[] args)
{
MainAsync().Wait();
Console.WriteLine("Done with test");
}
}
使用await
的代码更清晰,更易于维护。
此外,您不应将父/子任务与async
任务一起使用(例如AttachedToParent
)。它们并非旨在协同工作。
答案 2 :(得分:5)
我想补充一下我的答案,以补充已经被接受的答案。根据您要执行的操作,通常可以避免异步委托和包装任务的额外复杂性。例如,您的代码可以重新计算如下:
class Program
{
static async Task Test1()
{
System.Console.WriteLine("Enter Test");
await Task.Delay(100);
System.Console.WriteLine("Leave Test");
}
static async Task Test2()
{
System.Console.WriteLine("Enter callback");
await Task.Delay(1000);
System.Console.WriteLine("Leave callback");
}
static async Task Test()
{
await Test1(); // could do .ConfigureAwait(false) if continuation context doesn't matter
await Test2();
}
static void Main(string[] args)
{
Test().Wait();
Console.WriteLine("Done with test");
}
}