有人可以解释async / await吗?

时间:2013-01-06 00:13:31

标签: c# async-await

我开始在C#5.0中了解async / await,我根本不理解它。我不明白它如何用于并行。我尝试过以下非常基本的程序:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Task task1 = Task1();
            Task task2 = Task2();

            Task.WaitAll(task1, task2);

            Debug.WriteLine("Finished main method");
        }

        public static async Task Task1()
        {
            await new Task(() => Thread.Sleep(TimeSpan.FromSeconds(5)));
            Debug.WriteLine("Finished Task1");
        }

        public static async Task Task2()
        {
            await new Task(() => Thread.Sleep(TimeSpan.FromSeconds(10)));
            Debug.WriteLine("Finished Task2");
        }

    }
}

此程序只会阻止对Task.WaitAll()的调用,并且永远不会完成。有人可以向我解释原因吗?我确信我只是遗漏了一些简单的东西,或者只是没有正确的心理模型,而且那里的博客或MSDN文章都没有帮助。

5 个答案:

答案 0 :(得分:60)

我建议您从我的intro to async/await开始,然后跟进official MSDN documentation on TAP

正如我在我的介绍博客文章中提到的,有几个Task成员是TPL的遗留物,并且在纯async代码中没有用处。 new TaskTask.Start应替换为Task.Run(或TaskFactory.StartNew)。同样,Thread.Sleep应替换为Task.Delay

最后,我建议您不要使用Task.WaitAll;您的控制台应用只需使用Wait的{​​{1}} Task Task.WhenAll。通过所有这些更改,您的代码将如下所示:

class Program
{
    static void Main(string[] args)
    {
        MainAsync().Wait();
    }

    public static async Task MainAsync()
    {
        Task task1 = Task1();
        Task task2 = Task2();

        await Task.WhenAll(task1, task2);

        Debug.WriteLine("Finished main method");
    }

    public static async Task Task1()
    {
        await Task.Delay(5000);
        Debug.WriteLine("Finished Task1");
    }

    public static async Task Task2()
    {
        await Task.Delay(10000);
        Debug.WriteLine("Finished Task2");
    }
}

答案 1 :(得分:13)

了解C#任务,异步并等待

C#任务

Task类是一个异步任务包装器。 Thread.Sleep(1000)可以使线程停止运行1秒钟。虽然Task.Delay(1000)不会停止当前的工作。见代码:

public static void Main(string[] args){
    TaskTest();
}
private static void TaskTest(){
     Task.Delay(5000);
     System.Console.WriteLine("task done");
}

运行时,“任务完成”将立即显示。所以我可以假设Task中的每个方法都应该是异步的。如果我用Task.Run(()=> TaskTest()替换TaskTest(),那么在我附加一个Console.ReadLine()之前,任务完成都不会显示出来。在Run方法之后。

在内部,Task类表示状态机中的线程状态。状态机中的每个状态都有几个状态,如Start,Delay,Cancel和Stop。

async并等待

现在,您可能想知道所有Task是否都是异步的,Task.Delay的目的是什么?接下来,让我们通过使用async和await

来真正延迟正在运行的线程
public static void Main(string[] args){
     TaskTest();
     System.Console.WriteLine("main thread is not blocked");
     Console.ReadLine();
}
private static async void TaskTest(){
     await Task.Delay(5000);
     System.Console.WriteLine("task done");
}

异步告诉调用者,我是异步方法,不要等我。等待TaskTest()内部请求等待异步任务。现在,在运行之后,程序将等待5秒钟以显示任务完成文本。

取消任务

由于Task是一个状态机,因此必须有一种方法可以在任务运行时取消该任务。

static CancellationTokenSource tokenSource = new CancellationTokenSource();
public static void Main(string[] args){
    TaskTest();
    System.Console.WriteLine("main thread is not blocked");
    var input=Console.ReadLine();
    if(input=="stop"){
          tokenSource.Cancel();
          System.Console.WriteLine("task stopped");
     }
     Console.ReadLine();
}
private static async void TaskTest(){
     try{
          await Task.Delay(5000,tokenSource.Token);
     }catch(TaskCanceledException e){
          //cancel task will throw out a exception, just catch it, do nothing.
     }
     System.Console.WriteLine("task done");
}

现在,当程序运行时,您可以输入“stop”来取消延迟任务。

答案 2 :(得分:11)

你的任务永远不会完成,因为它们从未开始运行。

我会Task.Factory.StartNew创建一个任务并启动它。

public static async Task Task1()
{
  await Task.Factory.StartNew(() => Thread.Sleep(TimeSpan.FromSeconds(5)));
  Debug.WriteLine("Finished Task1");
}

public static async Task Task2()
{
  await Task.Factory.StartNew(() => Thread.Sleep(TimeSpan.FromSeconds(10)));
  Debug.WriteLine("Finished Task2");
}

作为旁注,如果您真的只是想在异步方法中暂停,则无需阻止整个线程,只需使用Task.Delay

public static async Task Task1()
{
  await Task.Delay(TimeSpan.FromSeconds(5));
  Debug.WriteLine("Finished Task1");
}

public static async Task Task2()
{
  await Task.Delay(TimeSpan.FromSeconds(10));
  Debug.WriteLine("Finished Task2");
}

答案 3 :(得分:7)

Async和await是标记代码位置的标记,控制应在任务(线程)完成后从哪里恢复。 这是一个详细的YouTube视频,以示范的方式解释了这个概念http://www.youtube.com/watch?v=V2sMXJnDEjM

如果您需要,您还可以阅读此coodeproject文章,该文章以更直观的方式解释相同内容。 http://www.codeproject.com/Articles/599756/Five-Great-NET-Framework-4-5-Features#Feature1:-“异步”和“等待”(Codemarkers)

答案 4 :(得分:0)

static void Main(string[] args)
{
    if (Thread.CurrentThread.Name == null)
        Thread.CurrentThread.Name = "Main";
    Console.WriteLine(Thread.CurrentThread.Name + "1");

    TaskTest();

    Console.WriteLine(Thread.CurrentThread.Name + "2");
    Console.ReadLine();
}


private async static void TaskTest()
{
    Console.WriteLine(Thread.CurrentThread.Name + "3");

    await Task.Delay(2000);
    if (Thread.CurrentThread.Name == null)
        Thread.CurrentThread.Name = "FirstTask";
    Console.WriteLine(Thread.CurrentThread.Name + "4");

    await Task.Delay(2000);
    if (Thread.CurrentThread.Name == null)
        Thread.CurrentThread.Name = "SecondTask";
    Console.WriteLine(Thread.CurrentThread.Name + "5");
}

如果您运行此程序,您将看到 await 将使用不同的线程。输出:

Main1
Main3
Main2
FirstTask4 // 2 seconds delay
SecondTask5 // 4 seconds delay

但是,如果我们删除两个 await 关键字,您会发现仅 async 并没有多大作用。输出:

Main1
Main3
Main4
Main5
Main2