理解 C # 中的异步/等待

我开始在 C # 5.0中学习异步/等待,但我一点也不理解它。我不明白它怎么能用于并行。我尝试了以下非常基本的程序:

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 文章是有帮助的。

57329 次浏览

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

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

我建议你开始与我的 ABC0/await简介和后续与 微软关于 TAP 的官方文档

正如我在介绍博客文章中提到的,有几个 Task成员是 TPL 的遗留成员,在纯 async代码中没有使用。new TaskTask.Start应替换为 Task.Run(或 TaskFactory.StartNew)。类似地,Thread.Sleep应该被 Task.Delay所取代。

最后,我建议您不要使用 Task.WaitAll; 您的控制台应用程序应该只在一个使用 Task.WhenAllTask上使用 Wait。对于所有这些更改,您的代码将如下所示:

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

异步和等待是标记,它们标记代码位置,在任务(线程)完成后,控制应从这些位置恢复。 下面是 youtube 上的一段视频,视频以演示的方式解释了这个概念的 http://www.youtube.com/watch?v=v2smxjndejm

如果你愿意,你也可以阅读这篇 codeproject 文章,它以更直观的方式解释了同样的内容。 Http://www.codeproject.com/articles/599756/five-great-net-framework-4-5-features#feature1:- 「 Async 」及「 Await 」(代码标记)

理解 C # 任务、异步和等待

C # 任务

任务类是异步任务包装器。线头。睡眠(1000)可以使线程停止运行1秒钟。当任务。延迟(1000)不会停止当前的工作。见代码:

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

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

在内部,Task 类表示状态机中的线程状态。状态机中的每个状态都有几个状态,如启动、延迟、取消和停止。

异步并等待

现在,您可能想知道如果所有 Task 都是异步的,那么 Task 的目的是什么。延迟?接下来,让我们通过使用异步来延迟正在运行的线程并等待

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”来取消延迟任务。

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