彻底搞懂C#异步编程 async和await的原理

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的方式维护,容易读懂。

原文地址:https://www.cnblogs.com/ligiggy/p/13630724.html