1.前提
熟练掌握Task并行编程。
2.用Task并行解释async和await异步
因为控制台有多线程操作的优化,因此这里选择winform来做示例。
测试代码如下所示:
有三个textbox,一个button
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TestAsyncAwait
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Button1_Click(object sender, EventArgs e)
{
TestAsync();
textBox3.Text = "333";
}
private async void TestAsync()
{
//Thread.Sleep(5000);//依然阻塞
await Task.Run(() =>
{
Thread.Sleep(2000);
this.Invoke((EventHandler)delegate { textBox1.Text = "1"; });
Thread.Sleep(2000);
});
this.Invoke((EventHandler)delegate { textBox2.Text = "22"; });
}
}
}
显示的顺序是:333,1,22
如果在设置textbox显示内容之前,通过Thread.CurrentThread.ManagedThreadId属性来获取当前线程ID。
可以得到textbox3所在为主线程,await之前也在主线程,await中和await后为新线程,这也是为什么在textbox1和textbox2的text加上invoke的原因。
简单来时,实际上async和await就是表示,遇到await之后,函数直接返回,然后剩下的部分等同于在一个新线程中运行。
使用Task并行编程的解释代码如下,将button按钮的click事件与TestAsync函数统一成TestTask函数
private void TestTask()
{
Task.Run(() =>
{
Task task = Task.Run(() =>
{
Thread.Sleep(2000);
this.Invoke((EventHandler)delegate { textBox1.Text = "1"; });
Thread.Sleep(2000);
});
Task.WaitAll(task);
this.Invoke((EventHandler)delegate { textBox2.Text = "22"; });
});
textBox3.Text = "333";
}
当然,上述代码也不完全等价async和await,只不过在实现功能上来说,没有差别。
具体的差别表现为,waitall之前的线程与waitall之后所在线程不在同一个线程。这个差别也揭示了async和await的另外一个优势,那就是节约线程,内部实现了线程池优化。
3.总结
如果你懂得Task并行编程或者Thread多线程编程,其实async和await的原理是不难的,没有什么神乎其神的操作。
async和await作为C#异步编程的语法糖,具有无可匹敌的优势,但是很多时候很多人不能理解用法,相比较而言直接使用Task并行编程会更加易懂。
我的建议是,如果是新项目可以使用async和await,让自己的代码更简洁;如果是老项目维护,建议还是使用Task的方式维护,容易读懂。