C#中async await異步關(guān)鍵字用法和異步的底層原理全解析
C#異步編程
一、異步編程基礎
異步編程是啥玩意兒
- 就是讓程序在干等著某些耗時操作(比如等網(wǎng)絡響應、讀寫文件啥的)的時候,能把線程騰出來干別的活兒,這樣程序就能更靈敏、更高效啦。
- 跟同步編程不一樣,同步編程就是老老實實等著操作完成才繼續(xù)往下走,線程就一直被占著,多浪費啊。
異步編程的好處
- 響應快:比如在做UI界面的時候,用了異步編程,界面就不會卡啦,用戶體驗賊棒。
- 省資源:不用讓線程一直干等著,資源利用率就上去了。
- 能扛更多活兒:面對一大堆并發(fā)操作的時候,異步編程能輕松搞定,擴展性杠杠滴。
二、異步方法的工作原理
異步方法咋被編譯的
- 你寫個
async修飾的方法,編譯器就把它變成一個狀態(tài)機啦。 - 狀態(tài)機會根據(jù)
await表達式把方法拆成好多個狀態(tài),就跟玩拼圖一樣。
狀態(tài)機是咋干活的
- 狀態(tài)機就是編譯器生成的一個類,它得記著異步方法執(zhí)行到哪兒了。
- 核心就是
MoveNext方法,它就像導演一樣,指揮著異步操作一步步往下走。 - 每碰到一個
await,就切換一下狀態(tài)。
await底層是咋實現(xiàn)的
await就整出個等待器(awaiter),專門等著異步操作完成。- 要是操作還沒完,
await就記下當前狀態(tài),等操作完了再繼續(xù)往下走。
三、代碼示例
用HttpClient干異步網(wǎng)絡請求
- 弄個
HttpClient對象,用來發(fā)HTTP請求。 - 用
GetStringAsync方法,就能異步拿到指定URL的網(wǎng)頁內(nèi)容啦。 - 把拿到的內(nèi)容打印出來,瞧一瞧成果。
using System;
using System.Net.Http;
using System.Threading.Tasks;
namespace asyncawait原理1
{
class Program
{
static async Task Main(string[] args)
{
using (HttpClient httpClient = new HttpClient())
{
string html = await httpClient.GetStringAsync("https://www.baidu.com");
Console.WriteLine(html);
}
}
}
}異步讀寫文件
- 用
File.WriteAllTextAsync方法,能把文本異步寫到指定路徑的文件里。 - 用
File.ReadAllTextAsync方法,就能把文件內(nèi)容異步讀出來。 - 把讀到的內(nèi)容打印出來,看看對不對。
using System;
using System.IO;
using System.Threading.Tasks;
namespace asyncawait原理1
{
class Program
{
static async Task Main(string[] args)
{
string txt = "hello world";
string filename = @"E:\temp\1.txt";
await File.WriteAllTextAsync(filename, txt);
Console.WriteLine("寫入成功");
string s = await File.ReadAllTextAsync(filename);
Console.WriteLine("文件內(nèi)容:" + s);
}
}
}四、編譯后的底層實現(xiàn)
用ILSpy反編譯DLL文件
- ILSpy就是個反編譯工具,能把DLL文件變回C#代碼,方便咱們研究。
- 把DLL文件加載到ILSpy里,就能看到編譯后的代碼啦。
[CompilerGenerated]
private sealed class <>c__DisplayClass0_0 : IAsyncStateMachine
{
public int <>1__state;
public AsyncTaskMethodBuilder <>t__builder;
public string[] args;
private string <>s__1;
private string <>s__3;
private string <>s__6;
private HttpClient <httpClient>__4;
private string <html>__5;
private string <txt>__2;
private string <filename>__7;
private void MoveNext()
{
int num = this.<>1__state;
try
{
TaskAwaiter<string> awaiter;
TaskAwaiter awaiter2;
switch (num)
{
default:
this.<httpClient>__4 = new HttpClient();
goto case 0;
case 0:
try
{
awaiter = this.<httpClient>__4.GetStringAsync("https://www.baidu.com").GetAwaiter();
if (!awaiter.IsCompleted)
{
num = this.<>1__state = 0;
this.<>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
return;
}
}
catch (Exception exception)
{
this.<>1__state = -2;
this.<>t__builder.SetException(exception);
return;
}
this.<html>__5 = awaiter.GetResult();
Console.WriteLine(this.<html>__5);
this.<txt>__2 = "hello yz";
this.<filename>__7 = @"E:\temp\1.txt";
awaiter2 = File.WriteAllTextAsync(this.<filename>__7, this.<txt>__2).GetAwaiter();
if (!awaiter2.IsCompleted)
{
num = this.<>1__state = 1;
this.<>t__builder.AwaitUnsafeOnCompleted(ref awaiter2, ref this);
return;
}
break;
case 1:
awaiter2 = this.<>s__1;
this.<>s__1 = null;
num = this.<>1__state = -1;
break;
}
awaiter2.GetResult();
Console.WriteLine("寫入成功");
this.<>s__3 = null;
awaiter = File.ReadAllTextAsync(this.<filename>__7).GetAwaiter();
if (!awaiter.IsCompleted)
{
num = this.<>1__state = 2;
this.<>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
return;
}
this.<>s__6 = awaiter.GetResult();
Console.WriteLine("文件內(nèi)容:" + this.<>s__6);
this.<>s__6 = null;
this.<>t__builder.SetResult();
}
catch (Exception exception)
{
this.<>1__state = -2;
this.<>t__builder.SetException(exception);
return;
}
this.<>1__state = -1;
}
void IAsyncStateMachine.MoveNext()
{
// This method is implemented by the compiler-generated code.
}
[DebuggerHidden]
private void SetStateMachine(IAsyncStateMachine stateMachine)
{
this.<>t__builder.SetStateMachine(stateMachine);
}
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
{
this.SetStateMachine(stateMachine);
}
}看看編譯后的狀態(tài)機代碼
- 分析狀態(tài)機類的結(jié)構(gòu),看看都有啥變量、
MoveNext方法長啥樣。 - 瞧瞧
awaiter咋用的,狀態(tài)咋切換的。
理解MoveNext方法是干啥的
MoveNext就是狀態(tài)機的發(fā)動機,它決定了異步方法咋執(zhí)行。- 在這個方法里,會根據(jù)當前狀態(tài)執(zhí)行對應的代碼,碰到
await就暫停,安排好后續(xù)咋繼續(xù)。
五、總結(jié)
異步方法編譯過程回顧
- 再嘮嘮
async方法咋被編譯成狀態(tài)機的,狀態(tài)機又咋根據(jù)await拆分方法、驅(qū)動異步操作的。
await到底在干啥
- 說白了,
await根本不是真的“等待”,而是靠狀態(tài)機和等待器來實現(xiàn)的異步協(xié)作。 - 強調(diào)一下異步編程的好處,比如響應快、省資源、能扛更多活兒,還有啥場景適合用它。
到此這篇關(guān)于C#中async await異步關(guān)鍵字用法和異步的底層原理的文章就介紹到這了,更多相關(guān)C# async await異步關(guān)鍵字內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#結(jié)合JavaScript實現(xiàn)上傳視頻到騰訊云點播平臺的操作方法
這篇文章主要介紹了C#結(jié)合JavaScript實現(xiàn)上傳視頻到騰訊云點播平臺,上傳視頻功能,主要要解決兩個問題,一是在服務端通過C#生成簽名和SDKID,二是在客戶端通過JavaScript上傳視頻到騰訊云點播服務器,感興趣的朋友跟隨小編一起看看吧2023-11-11
Unity中協(xié)程IEnumerator的使用方法介紹詳解
本文主要介紹了Unity中協(xié)程IEnumerator的使用方法介紹詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-06-06
Unity游戲開發(fā)實現(xiàn)背包系統(tǒng)的示例詳解
這篇文章主要為大家介紹了Unity游戲開發(fā)實現(xiàn)背包系統(tǒng)的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-08-08

