C# 将异步回调与 Task.ContinueWith 一起使用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18697167/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Use an async callback with Task.ContinueWith
提问by chouquette
I'm trying to play a bit with C#'s async/await/continuewith.
My goal is to have to have 2 tasks which are running in parallel, though which task is executing a sequence of action in order.
To do that, I planned to have a List<Task>
that represent the 2 (or more) tasks running in parallel, and to use ContinueWith
on each of the Task
My problem is that the callback in continue with seems not to be executed while the await taskList
has already returned.
我正在尝试使用 C# 的 async/await/continuewith。我的目标是必须有 2 个并行运行的任务,尽管哪个任务正在按顺序执行一系列操作。为此,我计划有一个List<Task>
代表并行运行的 2 个(或更多)任务,并ContinueWith
在每个任务上使用Task
我的问题是 continue 中的回调似乎没有在await taskList
已经返回时执行。
In order to summarize, here's a sample to illustrate what I'm expecting to happen:
为了总结一下,这里有一个示例来说明我期望发生的事情:
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");
}
}
The expected output would be
预期的输出将是
Enter Test
Leave Test
Enter callback
Leave callback
Done with test
However, the output is
然而,输出是
Enter Test
Leave Test
Enter callback
Done with test
Is there a way to make the Task on which ContinueWith
is called wait for the provided function to complete before being considered as done? ie. .Wait will wait for both tasks to be completed, the original one, and the one which is returned by ContinueWith
有没有办法让ContinueWith
被调用的任务在被认为完成之前等待提供的函数完成?IE。.Wait 将等待两个任务完成,原始任务和 ContinueWith 返回的任务完成
采纳答案by Nekresh
When chaining multiple tasks using the ContinueWith
method, your return type will be Task<T>
whereas T
is the return type of the delegate/method passed to ContinueWith
.
当使用链接多个任务的ContinueWith
方法,您的返回类型会Task<T>
,而T
是传递给委托/方法的返回类型ContinueWith
。
As the return type of an async delegate is a Task
, you will end up with a Task<Task>
and end up waiting for the async delegate to return you the Task
which is done after the first await
.
由于异步委托的返回类型是 a Task
,您将得到 aTask<Task>
并最终等待异步委托返回您Task
在第一个await
.
In order to correct this behaviour, you need to use the returned Task
, embedded in your Task<Task>
. Use the Unwrap
extension method to extract it.
为了纠正这种行为,您需要使用Task
嵌入在您的Task<Task>
. 使用Unwrap
扩展方法来提取它。
回答by noseratio
I'd like to add my answer to complement the answer which has already been accepted. Depending on what you're trying to do, often it's possible to avoid the added complexity of async delegates and wrapped tasks. For example, your code could be re-factored like this:
我想添加我的答案以补充已经被接受的答案。根据您尝试执行的操作,通常可以避免增加异步委托和包装任务的复杂性。例如,您的代码可以像这样重构:
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");
}
}
回答by Stephen Cleary
When you're doing async
programming, you should strive to replace ContinueWith
with await
, as such:
当您进行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");
}
}
The code using await
is much cleaner and easier to maintain.
使用的代码await
更简洁,更易于维护。
Also, you should not use parent/child tasks with async
tasks (e.g., AttachedToParent
). They were not designed to work together.
此外,您不应将父/子任务与async
任务(例如,AttachedToParent
)一起使用。它们不是为了协同工作而设计的。