C# 异步编程初体验(Async/Await)
前言
之前一直没搞懂 C# 的 async 到底是怎么玩的,一直以为和 node.js 的差不多,直到昨天问了一下 Elepover,才发现一直以来理解的 async 和 await 是错误的,于是写下一篇文章记录一下自己所想,说一下自己的初步理解,有错误之处敬请大佬指正。
开始
一开始一直认为,只要 C# 的类型是 Task,并且标志了 async 标识符,那么函数就会异步执行。其实不是的,是否异步执行还得取决于 async 的函数内部有无 await 的标识符。
错误的写法
我也不怕丢人,首先先来给大家看一下之前写的错误写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| using System; using System.Threading; using System.Threading.Tasks;
namespace ASyncProject { class Program { static async Task Main(string[] args) { var test1 = TestData1(); var test2 = TestData2(); Console.WriteLine(await test2); await test1; }
static async Task TestData1() { Console.WriteLine("1"); Thread.Sleep(10000); Console.WriteLine("test"); }
static async Task<string> TestData2() { Console.WriteLine("2"); Thread.Sleep(5000); return "233"; } } }
|
这里面的输出结果是
1 2 3 4 5 6
| 1 <10 seconds later> test 2 <5 seconds later> 233
|
我预想的结果是
1 2 3 4 5 6
| 1 2 <5 seconds later> 233 <5 seconds later> test
|
这显然不太对,这个不应该是异步方法吗?那这样和我直接写同步方法有什么区别呢?
修改后的写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| using System; using System.Threading; using System.Threading.Tasks;
namespace ASyncProject { class Program { static async Task Main(string[] args) { var test1 = TestData1(); var test2 = TestData2(); Console.WriteLine(await test2); await test1; }
static async Task TestData1() { Console.WriteLine("1"); await Task.Delay(10000); Console.WriteLine("test"); }
static async Task<string> TestData2() { Console.WriteLine("2"); await Task.Delay(5000); return "233"; } } }
|
这时候的输出结果就和此处一样了,即
1 2 3 4 5 6
| 1 2 <5 seconds later> 233 <5 seconds later> test
|
看到这里,我想不懂的话也大概明白是什么意思了。那么,再来做个试验?
async 中的同步
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| using System; using System.Threading; using System.Threading.Tasks;
namespace ASyncProject { class Program { static async Task Main(string[] args) { var test1 = TestData1(); var test2 = TestData2(); Console.WriteLine(await test2); await test1; }
static async Task TestData1() { Console.WriteLine("1"); Thread.Sleep(2000); await Task.Delay(10000); Console.WriteLine("test"); }
static async Task<string> TestData2() { Console.WriteLine("2"); await Task.Delay(5000); Thread.Sleep(2000); return "233"; } } }
|
这次的输出结果为
1 2 3 4 5 6 7
| 1 <2 seconds later> 2 <7 seconds later> 233 <3 seconds later> test
|
从中我们看到,在 var test1 = TestData1(); 的时候,实际上程序是进入了 TestData1 的方法中,并逐语句地往下执行,如果是同步的语句就按照同步的方法来执行。TestData1()先执行等待 2 秒,继续执行下一句,直到。。遇到 async 函数的第一个 await
这时候就类似于开了一个新的线程,或者可以说 TestData1() 让出了他的控制权,交还给 Main(),让 Main()继续执行下一句语句,也就是 TestData2(),但是此时 TestData1() 自己还在执行,也就是说类似于分开了一个分支,TestData1()就乖乖等待着 Task.Delay(10000)完成,Main()继续跑
TestData2()也是像 TestData1()一样逐个执行下一句,直到遇到 await,TestData2()也让出了他的控制权,Main()继续执行下一行,此时 Main()也遇到 await 了
Main()就等待 test2 的结果返回,然后输出到控制台上。
.Wait() ?
刚才试到 async 里面的 await,那么用.Wait()会怎样呢
我们仅对 TestData1()的 await 做修改,改成.Wait()看看会怎样
1 2 3 4 5 6 7
| static async Task TestData1() { Console.WriteLine("1"); Thread.Sleep(2000); Task.Delay(10000).Wait(); Console.WriteLine("test"); }
|
此时结果为
1 2 3 4
| 1 <12 seconds later> test <...>
|
这时候.Wait()就相当于变成同步执行的了,它并没有遇到它想要的 await,所以它还不能把控制权交给 Main()。此时虽然说 TestData1()也等待了,但 Main()也要跟着它一起等,等到出现那个 await,Main()才能跟 TestData1()分开,不然 Main()只能看着 TestData() 结束它自己。(悲)
后言
这就是我大概理解的 async 和 await 了,如果发现有错误请求大佬指正,果果很希望得到大家的指教 QwQ