async / await和C#中的Task / Wait是一样的吗?

时间:2013-11-14 17:35:48

标签: c# task async-await

我学会了比Task / async轻松使用await。现在,我正在尝试使用Task来学习async / await

    static void Main(string[] args)
    {
        Console.ReadKey(true);
        //Magic1(); 
        Magic2();
        Console.WriteLine("{0}", DateTime.Now.ToString());
        Console.ReadKey(true);
    }

    static async void Magic1()
    {
        var taskA = GetDataAsync();
        var taskB = GetDataAsync();
        var taskC = GetDataAsync();

        Console.WriteLine("a: " + await taskA);
        Console.WriteLine("b: " + await taskB);
        Console.WriteLine("c: " + await taskC);
    }

    static Task Magic2()
    {
        return Task.Run(() =>
        {
            var taskA = GetDataAsync();
            var taskB = GetDataAsync();
            var taskC = GetDataAsync();

            Task.WaitAll(new Task[] { taskA, taskB, taskC });

            Console.WriteLine("a: " + taskA.Result);
            Console.WriteLine("b: " + taskB.Result);
            Console.WriteLine("c: " + taskC.Result);
        });
    }

    static Task<string> GetDataAsync()
    {
        return Task.Run(() => 
        {
            var startTime = DateTime.Now;
            for (var i = 0; i < 1000000000; i++)
            {
            }
            var endTime = DateTime.Now;
            return startTime.ToString() + " to " + endTime.ToString() + " is " + (endTime - startTime).ToString();
        });
    }

我创建了两个似乎做同样事情的方法,我的问题是:

1)Magic1Magic2在引擎盖下是一样的吗?

2)如果它们不相同,我可以将Magic1转换为不使用asyncawait关键字执行相同操作的方法吗?

2 个答案:

答案 0 :(得分:4)

  

现在,我正在尝试使用我在Task中的知识来学习async / await。

我真的建议你这样做。虽然基于任务的并行性(.NET 4.0)和基于任务的异步模式(async / await)使用相同的类型(Task),但它们完全不同。他们解决不同的问题,并采用不同的工作方式。

相反,我建议您假装对Task类型一无所知,并从我的async intro开始。在我的async介绍结尾处有几个后续资源,包括对此功能非常有用的MSDN文档。

如果你真的熟悉延续,你可以(大多数时候)认为await意思是“将此方法的其余部分重写为延续,并使用当前SynchronizationContext或{{来安排它1}}”。但即使这只是一个近似值;有很多边缘案例。这与在TaskScheduler中执行Task.Wait[All]完全不同。

答案 1 :(得分:1)

两种方法之间的差异:

  • 代码运行的位置。 Magic2将在线程池而不是调用者的同步上下文中运行,因为您(不必要地)使用了Task.Run。如果您正在编写UI代码,则可能导致Magic2失败。
  • 阻断即可。 Magic1会阻止调用者,直到完成。编写异步代码时通常会出错。即使您删除了Task.Run,​​Magic2也不会阻止调用者。
  • 增量工作。如果taskB需要更长的时间来完成,那么不会延迟Magic2打印taskA的结果。 Magic1等待所有三个任务完成,因此在taskB完成之前它不会打印taskA。