46

我正在尝试使用 C# 的 async/await/continuewith。我的目标是必须有 2 个并行运行的任务,尽管哪个任务按顺序执行一系列动作。为此,我计划让一个List<Task>代表 2 个(或更多)任务并行运行,并ContinueWith在每个问题上使用Task 我的问题是 continue with 中的回调似乎在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被调用的任务在被视为完成之前等待提供的函数完成?IE。.Wait 将等待两个任务完成,原始任务和 ContinueWith 返回的任务

4

3 回答 3

51

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

由于异步委托的返回类型是 a Task,因此您最终将得到 aTask<Task>并最终等待异步委托返回您,Task这是在第一个 . 之后完成的await

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

于 2013-09-09T11:42:10.497 回答
29

当你在做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");
  }
}

使用的代码await更干净,更易于维护。

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

于 2013-09-09T12:19:29.957 回答
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");
    }
}
于 2013-09-09T12:12:16.337 回答