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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 12:56:58  来源:igfitidea点击:

Use an async callback with Task.ContinueWith

c#async-await

提问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 ContinueWithon each of the TaskMy problem is that the callback in continue with seems not to be executed while the await taskListhas 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 ContinueWithis 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 ContinueWithmethod, your return type will be Task<T>whereas Tis 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 Taskwhich 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 Unwrapextension 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 asyncprogramming, you should strive to replace ContinueWithwith await, as such:

当您进行async编程时,您应该努力替换ContinueWithawait,如下所示:

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 awaitis much cleaner and easier to maintain.

使用的代码await更简洁,更易于维护。

Also, you should not use parent/child tasks with asynctasks (e.g., AttachedToParent). They were not designed to work together.

此外,您不应将父/子任务与async任务(例如,AttachedToParent)一起使用。它们不是为了协同工作而设计的。