对 Task.ContinueWith 使用异步回调

本文关键字:异步 回调 Task ContinueWith | 更新日期: 2023-09-27 18:30:36

我正在尝试使用C#的async/await/continuewith。我的目标是必须有 2 个并行运行的任务,尽管哪个任务正在按顺序执行一系列操作。为此,我计划有一个表示并行运行的 2 个(或更多)任务的List<Task>,并在每个Task上使用ContinueWith我的问题是,当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的任务等待提供的功能完成,然后再被视为完成?等待将等待两个任务完成,原始任务和继续返回

对 Task.ContinueWith 使用异步回调

的任务

使用 ContinueWith 方法链接多个任务时,返回类型将是Task<T>,而T是传递给ContinueWith的委托/方法的返回类型。

由于异步委托的返回类型是 Task ,您最终会得到一个Task<Task>,并最终等待异步委托返回在第一次await之后完成的Task

为了纠正这种行为,您需要使用嵌入在Task<Task>中的返回Task。使用 Unwrap 扩展方法提取它。

当你做async编程时,你应该努力用await替换ContinueWith,如下所示:

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 )。它们不是为协同工作而设计的。

我想

添加我的答案来补充已经被接受的答案。根据您要执行的操作,通常可以避免异步委托和包装任务增加的复杂性。例如,可以像这样重构代码:

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");
    }
}