Async和await异步编程

时间:2023-02-07 23:31:36

对于同步的代码,大家肯定都不陌生,因为我们平常写的代码大部分都是同步的,然而同步代码却存在一个很严重的问题,例如我们向一个Web服务器发出一个请求时,如果我们发出请求的代码是同步实现的话,这时候我们的应用程序就会处于等待状态,直到收回一个响应信息为止,然而在这个等待的状态,对于用户不能操作任何的UI界面以及也没有任何的消息,如果我们试图去操作界面时,此时我们就会看到"应用程序为响应"的信息(在应用程序的窗口旁),相信大家在平常使用桌面软件或者访问web的时候,肯定都遇到过这样类似的情况的,对于这个,大家肯定会觉得看上去非常不舒服。引起这个原因正是因为代码的实现是同步实现的,所以在没有得到一个响应消息之前,界面就成了一个"卡死"状态了,所以这对于用户来说肯定是不可接受的,因为如果我要从服务器上下载一个很大的文件时,此时我们甚至不能对窗体进行关闭的操作的。为了具体说明同步代码存在的问题(造成界面开始),下面通过一个程序让大家更形象地看下问题所在:
  

public partial class Form1 : Form
{
private int method()
{
Thread.Sleep(10000);
return 100;
}

private void button1_Click(object sender, EventArgs e)
{

int r = method();
this.textBox1.Text = r.ToString();
}

private void button2_Click(object sender, EventArgs e)
{
this.textBox2.Text = "hello world";
}
}

当我们点击button1时,此时我们如果再点击button2时,将不会输出hello world,如果继续点击界面,可能就会出现未响应,造成一个卡死的状态。如下图所示:

Async和await异步编程

如果我们通过async和await关键字来对上面程序进行异步编程,就不会出现上述情况了。下面通过代码来了解下如何使用async和await关键字来实现异步编程。

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private async Task<int> methodAsync()
{
await Task.Delay(10000);
return 200;
}

private async void button1_Click(object sender, EventArgs e)

{
int r= await methodAsync();
this.textBox1.Text = r.ToString();
}

private void button2_Click(object sender, EventArgs e)
{
this.textBox2.Text = "hello world";
}
}

此时我们在点击button1后再点击button2就会立刻在textBox2上显示hello world内容,不会卡死,10s后,textBox1将显示200.如下图所示:

Async和await异步编程

Async和await异步编程

我们对比下上面使用async和await关键字来实现异步编程,有没有发现使用async和await关键字的异步实现和同步代码的实现很像,只是异步实现中多了async和await关键字和调用的方法都多了async后缀而已。有没有觉得使用 async和await使异步编程更简单,就像我们在写同步代码一样,并且代码的coding思路也是和同步代码一样,这样就避免考虑在APM中委托的回调等复杂的问题,以及在EAP中考虑各种事件的定义。从代码部分我们可以看出async和await的使用确实很简单,我们就如在写同步代码一般。

分析完之后,下面再分享下几个关于async和await常问的问题

问题一:是不是写了async关键字的方法就代表该方法是异步方法,不会堵塞线程呢?

答: 不是的,对于只标识async关键字的(指在方法内没有出现await关键字)的方法,调用线程会把该方法当成同步方法一样执行,所以然而会堵塞GUI线程,只有当async和await光剑子同时出现,该方法才被转换为异步方法处理。

问题二:“async”关键字会导致调用方法用线程池线程运行吗?

答: 不会,被async关键字标识的方法不会影响方法是同步还是异步运行并完成,而是,它使方法可被分割成多个片段,其中一些片段可能异步运行,这样这个方法可能异步完成。这些片段界限就出现在方法内部显示使用”await”关键字的位置处。所以,如果在标记了”async”的方法中没有显示使用”await”,那么该方法只有一个片段,并且将以同步方式运行并完成。在await关键字出现的前面部分代码和后面部分代码都是同步执行的(即在调用线程上执行的,也就是GUI线程,所以不存在跨线程访问控件的问题),await关键处的代码片段是在线程池线程上执行。总结为——使用async和 await关键字实现的异步方法,此时的异步方法被分成了多个代码片段去执行的,而不是像之前的异步编程模型(APM)和EAP那样,使用线程池线程去执行一整个方法。