0%

C# 异步编程初体验(Async/Await)

C# 异步编程初体验(Async/Await)

前言

之前一直没搞懂 C# 的 async 到底是怎么玩的,一直以为和 node.js 的差不多,直到昨天问了一下 Elepover,才发现一直以来理解的 async 和 await 是错误的,于是写下一篇文章记录一下自己所想,说一下自己的初步理解,有错误之处敬请大佬指正。

开始

一开始一直认为,只要 C# 的类型是 Task,并且标志了 async 标识符,那么函数就会异步执行。其实不是的,是否异步执行还得取决于 async 的函数内部有无 await 的标识符。

错误的写法

我也不怕丢人,首先先来给大家看一下之前写的错误写法

1
using System;
2
using System.Threading;
3
using System.Threading.Tasks;
4
5
namespace ASyncProject
6
{
7
    class Program
8
    {
9
        static async Task Main(string[] args)
10
        {
11
            var test1 = TestData1();
12
            var test2 = TestData2();
13
            Console.WriteLine(await test2);
14
            await test1;
15
        }
16
17
        static async Task  TestData1()
18
        {
19
            Console.WriteLine("1");
20
            Thread.Sleep(10000);
21
            Console.WriteLine("test");
22
        }
23
24
        static async Task<string> TestData2()
25
        {
26
            Console.WriteLine("2");
27
            Thread.Sleep(5000);
28
            return "233";
29
        }
30
    }
31
}

这里面的输出结果是

1
1
2
<10 seconds later>
3
test
4
2
5
<5 seconds later>
6
233

我预想的结果是

1
1
2
2
3
<5 seconds later>
4
233
5
<5 seconds later>
6
test

这显然不太对,这个不应该是异步方法吗?那这样和我直接写同步方法有什么区别呢?

修改后的写法

1
using System;
2
using System.Threading;
3
using System.Threading.Tasks;
4
5
namespace ASyncProject
6
{
7
    class Program
8
    {
9
        static async Task Main(string[] args)
10
        {
11
            var test1 = TestData1();
12
            var test2 = TestData2();
13
            Console.WriteLine(await test2);
14
            await test1;
15
        }
16
17
        static async Task TestData1()
18
        {
19
            Console.WriteLine("1");
20
            await Task.Delay(10000);
21
            Console.WriteLine("test");
22
        }
23
24
        static async Task<string> TestData2()
25
        {
26
            Console.WriteLine("2");
27
            await Task.Delay(5000);
28
            return "233";
29
        }
30
    }
31
}

这时候的输出结果就和此处一样了,即

1
1
2
2
3
<5 seconds later>
4
233
5
<5 seconds later>
6
test

看到这里,我想不懂的话也大概明白是什么意思了。那么,再来做个试验?

async 中的同步

1
using System;
2
using System.Threading;
3
using System.Threading.Tasks;
4
5
namespace ASyncProject
6
{
7
    class Program
8
    {
9
        static async Task Main(string[] args)
10
        {
11
            var test1 = TestData1();
12
            var test2 = TestData2();
13
            Console.WriteLine(await test2);
14
            await test1;
15
        }
16
17
        static async Task TestData1()
18
        {
19
            Console.WriteLine("1");
20
						Thread.Sleep(2000);
21
            await Task.Delay(10000);
22
            Console.WriteLine("test");
23
        }
24
25
        static async Task<string> TestData2()
26
        {
27
            Console.WriteLine("2");
28
            await Task.Delay(5000);
29
            Thread.Sleep(2000);
30
            return "233";
31
        }
32
    }
33
}

这次的输出结果为

1
1
2
<2 seconds later>
3
2
4
<7 seconds later>
5
233
6
<3 seconds later>
7
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
static async Task TestData1()
2
  {
3
      Console.WriteLine("1");
4
      Thread.Sleep(2000);
5
      Task.Delay(10000).Wait();
6
      Console.WriteLine("test");
7
  }

此时结果为

1
1
2
<12 seconds later>
3
test
4
<...>

这时候.Wait()就相当于变成同步执行的了,它并没有遇到它想要的 await,所以它还不能把控制权交给 Main()。此时虽然说 TestData1()也等待了,但 Main()也要跟着它一起等,等到出现那个 await,Main()才能跟 TestData1()分开,不然 Main()只能看着 TestData() 结束它自己。(悲)

后言

这就是我大概理解的 async 和 await 了,如果发现有错误请求大佬指正,果果很希望得到大家的指教 QwQ