日韩欧美人妻无码精品白浆,www.大香蕉久久网,狠狠的日狠狠的操,日本好好热在线观看

LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開(kāi)發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

揭秘C#異步編程核心機(jī)制:從狀態(tài)機(jī)到線程池的全面拆解

freeflydom
2025年6月11日 9:35 本文熱度 488

1. 異步編程的基礎(chǔ)

1.1 什么是異步編程?

異步編程是一種編程范式,旨在解決傳統(tǒng)同步編程中因等待操作(如I/O或計(jì)算)而導(dǎo)致的線程阻塞問(wèn)題。在同步模型中,調(diào)用一個(gè)耗時(shí)操作會(huì)使當(dāng)前線程暫停,直到操作完成。而在異步模型中,程序可以在等待操作完成的同時(shí)繼續(xù)執(zhí)行其他任務(wù),從而提高資源利用率和程序的響應(yīng)性。

例如,在處理網(wǎng)絡(luò)請(qǐng)求時(shí),同步調(diào)用會(huì)阻塞線程直到響應(yīng)返回,而異步調(diào)用則允許線程去做其他工作,待響應(yīng)到達(dá)時(shí)再處理結(jié)果。這種特性在I/O密集型場(chǎng)景(如文件讀寫(xiě)、網(wǎng)絡(luò)通信)和高并發(fā)場(chǎng)景(如Web服務(wù)器)中尤為重要。

1.2 C#中的asyncawait

C#通過(guò)asyncawait關(guān)鍵字簡(jiǎn)化了異步編程的編寫(xiě):

  • **async**:標(biāo)記一個(gè)方法為異步方法,表示它可能包含異步操作。通常與TaskTask<T>返回類(lèi)型一起使用。
  • **await**:暫停異步方法的執(zhí)行,等待某個(gè)異步操作(通常是Task)完成,同時(shí)釋放當(dāng)前線程。

以下是一個(gè)簡(jiǎn)單的異步方法示例:

public async Task<int> GetNumberAsync()
{
    await Task.Delay(1000); // 模擬1秒延遲
    return 42;
}

調(diào)用此方法時(shí),await Task.Delay(1000)會(huì)暫停方法執(zhí)行,但不會(huì)阻塞線程。線程會(huì)被釋放,待延遲完成后,方法繼續(xù)執(zhí)行并返回結(jié)果。

2. 編譯器的魔力:狀態(tài)機(jī)

2.1 異步方法的轉(zhuǎn)換

盡管asyncawait讓異步代碼看起來(lái)像同步代碼,但這背后是C#編譯器的復(fù)雜工作。當(dāng)您編寫(xiě)一個(gè)async方法時(shí),編譯器會(huì)將其轉(zhuǎn)換為一個(gè)狀態(tài)機(jī)(State Machine),負(fù)責(zé)管理異步操作的執(zhí)行流程。

狀態(tài)機(jī)是一個(gè)自動(dòng)機(jī),它將方法的執(zhí)行分解為多個(gè)狀態(tài),每個(gè)狀態(tài)對(duì)應(yīng)代碼中的一個(gè)執(zhí)行階段(通常是await點(diǎn))。狀態(tài)機(jī)通過(guò)暫停和恢復(fù)機(jī)制,確保方法能在異步操作完成時(shí)正確繼續(xù)執(zhí)行。

2.2 狀態(tài)機(jī)的結(jié)構(gòu)

編譯器生成的的狀態(tài)機(jī)通常是一個(gè)結(jié)構(gòu)體(在發(fā)布模式下以減少分配開(kāi)銷(xiāo))或類(lèi)(在調(diào)試模式下以便調(diào)試),實(shí)現(xiàn)了IAsyncStateMachine接口。該接口定義了兩個(gè)方法:

  • **MoveNext**:驅(qū)動(dòng)狀態(tài)機(jī)執(zhí)行,是狀態(tài)機(jī)的核心邏輯。
  • **SetStateMachine**:用于跨AppDomain場(chǎng)景,通常不直接使用。

狀態(tài)機(jī)包含以下關(guān)鍵字段:

  • **state**:一個(gè)整數(shù),表示當(dāng)前狀態(tài)(如-1表示初始,0、1等表示等待點(diǎn),-2表示完成)。
  • **builder**:AsyncTaskMethodBuilderAsyncTaskMethodBuilder<T>,用于構(gòu)建和完成返回的Task。
  • **awaiter**:表示當(dāng)前等待的異步操作(如TaskAwaiter)。

2.3 狀態(tài)機(jī)的執(zhí)行流程

GetNumberAsync為例,其狀態(tài)機(jī)的執(zhí)行流程如下:

  1. 初始狀態(tài)(state = -1):方法開(kāi)始執(zhí)行。
  2. **遇到await**:檢查Task.Delay(1000)是否已完成。
    • 如果未完成,狀態(tài)機(jī)將:
      • 更新state為0(表示等待第一個(gè)await)。
      • 注冊(cè)一個(gè)延續(xù)(continuation),等待任務(wù)完成時(shí)回調(diào)。
      • 返回,釋放線程。
    • 如果已完成,直接繼續(xù)執(zhí)行。
  3. 任務(wù)完成:任務(wù)完成時(shí)觸發(fā)延續(xù),狀態(tài)機(jī)恢復(fù):
    • 檢查state值為0,跳轉(zhuǎn)到await后的代碼。
    • 獲取結(jié)果,繼續(xù)執(zhí)行。
  4. 方法完成(state = -2):設(shè)置返回值并完成Task。

以下是簡(jiǎn)化的狀態(tài)機(jī)偽代碼:

private struct GetNumberAsyncStateMachine : IAsyncStateMachine
{
    public int state; // 狀態(tài)字段
    public AsyncTaskMethodBuilder<int> builder; // Task構(gòu)建器
    private TaskAwaiter awaiter; // 等待器
    public void MoveNext()
    {
        int result;
        try
        {
            if (state == -1) // 初始狀態(tài)
            {
                awaiter = Task.Delay(1000).GetAwaiter();
                if (!awaiter.IsCompleted) // 任務(wù)未完成
                {
                    state = 0; // 等待狀態(tài)
                    builder.AwaitUnsafeOnCompleted(ref awaiter, ref this); // 注冊(cè)延續(xù)
                    return;
                }
                goto resume0; // 已完成,直接繼續(xù)
            }
            if (state == 0) // 從await恢復(fù)
            {
resume0:
                awaiter.GetResult(); // 獲取結(jié)果
                result = 42;
                builder.SetResult(result); // 設(shè)置返回值
                state = -2; // 完成
            }
        }
        catch (Exception ex)
        {
            builder.SetException(ex); // 設(shè)置異常
            state = -2;
        }
    }
}

2.4 狀態(tài)機(jī)圖示

為了更直觀地理解,我們將從宏觀角度理解狀態(tài)機(jī)(State Machine)的組件及其交互邏輯,以下是一個(gè)狀態(tài)機(jī)流程圖:

3. 任務(wù)(Task)的奧秘

3.1 Task的定義

Task是C#異步編程的核心類(lèi),位于System.Threading.Tasks命名空間。它表示一個(gè)異步操作,可以是計(jì)算任務(wù)、I/O操作或任何異步工作。Task<T>是帶返回值的版本。

3.2 Task的生命周期

Task有以下?tīng)顟B(tài)(通過(guò)Task.Status屬性查看):

  • Created:已創(chuàng)建但未調(diào)度。
  • WaitingToRun:已調(diào)度但等待執(zhí)行。
  • Running:正在執(zhí)行。
  • RanToCompletion:成功完成。
  • Faulted:發(fā)生異常。
  • Canceled:被取消。

3.3 Task的調(diào)度

Task的執(zhí)行由任務(wù)調(diào)度器(TaskScheduler)管理。默認(rèn)調(diào)度器使用線程池(ThreadPool)來(lái)執(zhí)行任務(wù)。線程池是一個(gè)預(yù)分配的線程集合,可以重用線程,避免頻繁創(chuàng)建和銷(xiāo)毀線程的開(kāi)銷(xiāo)。

創(chuàng)建Task的方式包括:

  • **Task.Run**:將任務(wù)調(diào)度到線程池執(zhí)行。
  • **Task.Factory.StartNew**:更靈活的創(chuàng)建方式。
  • 異步方法返回的Task:由AsyncTaskMethodBuilder管理。

3.4 I/O-bound vs CPU-bound任務(wù)

  • I/O-bound任務(wù):如網(wǎng)絡(luò)請(qǐng)求(HttpClient.GetAsync)、文件操作(File.ReadAllTextAsync),使用異步I/O機(jī)制,通常不占用線程,而是通過(guò)操作系統(tǒng)提供的回調(diào)完成。
  • CPU-bound任務(wù):如復(fù)雜計(jì)算(Task.Run(() => Compute())),在線程池線程上執(zhí)行。

例如:

public async Task<string> FetchDataAsync()
{
    using var client = new HttpClient();
    return await client.GetStringAsync("https://example.com"); // I/O-bound
}
public Task<int> ComputeAsync()
{
    return Task.Run(() => { /* CPU密集型計(jì)算 */ return 42; }); // CPU-bound
}

4. 線程管理和上下文

異步編程的核心目標(biāo)是避免線程阻塞,而不是頻繁切換線程。想象一個(gè)應(yīng)用程序,比如一個(gè)帶有用戶(hù)界面的程序,主線程(通常是UI線程)負(fù)責(zé)處理用戶(hù)交互、繪制界面等任務(wù)。如果某個(gè)操作(比如網(wǎng)絡(luò)請(qǐng)求或文件讀寫(xiě))需要很長(zhǎng)時(shí)間,主線程如果傻等,就會(huì)導(dǎo)致程序卡頓。異步編程通過(guò)將耗時(shí)任務(wù)“卸載”出去,讓主線程繼續(xù)執(zhí)行其他工作,從而保持程序的響應(yīng)性。

在C#中,asyncawait關(guān)鍵字極大簡(jiǎn)化了異步編程,但其底層依賴(lài)于狀態(tài)機(jī)任務(wù)調(diào)度

異步并不總是意味著線程切換,而是通過(guò)合理的任務(wù)分配和通知機(jī)制實(shí)現(xiàn)非阻塞。

4.1 線程切換是如何發(fā)生的?

異步操作中是否涉及線程切換,取決于任務(wù)的類(lèi)型和執(zhí)行環(huán)境。我們可以把任務(wù)分為兩類(lèi):

  1. I/O密集型任務(wù)(I/O-bound)

    • 比如網(wǎng)絡(luò)請(qǐng)求、文件讀寫(xiě)等,這些任務(wù)通常由系統(tǒng)內(nèi)核或線程池線程在后臺(tái)處理。
    • 主線程發(fā)起請(qǐng)求后,立即返回,不會(huì)被阻塞。當(dāng)任務(wù)完成時(shí),系統(tǒng)通過(guò)回調(diào)或延續(xù)(continuation)通知主線程。
    • 例子:你調(diào)用HttpClient.GetAsync(),主線程發(fā)起請(qǐng)求后繼續(xù)執(zhí)行,網(wǎng)絡(luò)操作由底層線程池或系統(tǒng)完成,結(jié)果回來(lái)時(shí)觸發(fā)延續(xù)。
  2. CPU密集型任務(wù)(CPU-bound)

    • 比如復(fù)雜的數(shù)學(xué)計(jì)算,這種任務(wù)可以交給線程池線程執(zhí)行,避免阻塞主線程。
    • 例子:用Task.Run()將計(jì)算任務(wù)交給線程池,主線程繼續(xù)處理其他邏輯。

需要注意的是,在某些情況下,異步操作可能根本不涉及線程切換。例如,一個(gè)同步完成的I/O操作(比如從緩存讀取數(shù)據(jù))或使用Task.Yield(),都可能在同一線程上完成。

4.2 C#中async/await的工作原理

在C#中,當(dāng)你使用asyncawait時(shí),編譯器會(huì)將方法轉(zhuǎn)化為一個(gè)狀態(tài)機(jī)。這個(gè)狀態(tài)機(jī)負(fù)責(zé):

  • await處暫停方法的執(zhí)行。
  • 設(shè)置一個(gè)延續(xù)(continuation),表示任務(wù)完成后要繼續(xù)執(zhí)行的代碼。
  • 當(dāng)任務(wù)完成時(shí),觸發(fā)狀態(tài)機(jī)恢復(fù)執(zhí)行,從await后的代碼繼續(xù)。

關(guān)鍵機(jī)制

  • 同步上下文(SynchronizationContext):在UI應(yīng)用中,await會(huì)捕獲當(dāng)前的同步上下文(通常是UI線程上下文),確保任務(wù)完成后的延續(xù)回到UI線程執(zhí)行,以便更新界面。
  • ConfigureAwait(false):如果不需要回到原線程(比如在服務(wù)器端代碼中),可以用這個(gè)選項(xiàng)讓延續(xù)在線程池線程上執(zhí)行,減少線程切換開(kāi)銷(xiāo)。

4.3 線程切換的開(kāi)銷(xiāo)

線程切換涉及上下文切換(保存和恢復(fù)線程狀態(tài)),開(kāi)銷(xiāo)不小。因此,異步編程的目標(biāo)是減少不必要的切換。比如:

  • 在UI應(yīng)用中,延續(xù)默認(rèn)回到UI線程,確保界面更新安全。
  • 在服務(wù)器端,ConfigureAwait(false)可以避免切換回原上下文,提升性能。

異步編程通過(guò)將耗時(shí)任務(wù)委托給后臺(tái)線程或系統(tǒng)內(nèi)核,避免主線程阻塞,而不是依賴(lài)頻繁的線程切換。你的比喻基本合理,尤其是“主線程交給另一輛車(chē)”的想法,但需要強(qiáng)調(diào)主線程不等待、結(jié)果通過(guò)信號(hào)通知的特點(diǎn)。改進(jìn)后的比喻更準(zhǔn)確地反映了異步的非阻塞特性和線程管理機(jī)制。

4.4 幾個(gè)重要概念

4.4.1 同步上下文(SynchronizationContext)

同步上下文是一個(gè)抽象類(lèi),用于在特定線程或上下文中執(zhí)行代碼。在UI應(yīng)用程序(如WPF、WinForms)中,UI線程有一個(gè)特定的SynchronizationContext,確保UI更新在UI線程上執(zhí)行。

await默認(rèn)會(huì)捕獲當(dāng)前的同步上下文,并在任務(wù)完成后恢復(fù)到該上下文執(zhí)行后續(xù)代碼。例如:

private async void Button_Click(object sender, EventArgs e)
{
    await Task.Delay(1000);
    label.Text = "Done"; // 自動(dòng)恢復(fù)到UI線程
}

4.4.2 ConfigureAwait 的作用

ConfigureAwait(bool continueOnCapturedContext)允許控制是否恢復(fù)到原始上下文:

  • **true**(默認(rèn)):恢復(fù)到捕獲的上下文。
  • **false**:在任務(wù)完成后的任意線程上繼續(xù)執(zhí)行。

在服務(wù)器端代碼中,使用ConfigureAwait(false)可以避免不必要的上下文切換:

public async Task<string> GetDataAsync()
{
    await Task.Delay(1000).ConfigureAwait(false);
    return "Data"; // 不恢復(fù)到原始上下文
}

即使有人對(duì)async/await的工作流程有了相當(dāng)不錯(cuò)的理解,但對(duì)于嵌套異步調(diào)用鏈的行為仍有很多困惑。尤其是討論到在庫(kù)代碼中何時(shí)以及如何使用ConfigureAwait(false)時(shí),這種困惑更為明顯。接下來(lái)我們通過(guò)下面的流程圖,探索一個(gè)非常具體的示例,并深入理解每一個(gè)執(zhí)行步驟:

https://vkontech.com/exploring-the-async-await-state-machine-series-overview/

4.4.3 執(zhí)行上下文(ExecutionContext)

執(zhí)行上下文維護(hù)線程的執(zhí)行環(huán)境,包括安全上下文、調(diào)用上下文等。在異步操作中,ExecutionContext會(huì)被捕獲并在延續(xù)時(shí)恢復(fù),確保線程局部數(shù)據(jù)(如ThreadLocal<T>)的正確性。

5. 異常處理機(jī)制

5.1 異常的捕獲和傳播

在異步方法中,拋出的異常會(huì)被捕獲并存儲(chǔ)在返回的Task中。當(dāng)awaitTask時(shí),異常會(huì)被重新拋出。例如:

public async Task ThrowAsync()
{
    await Task.Delay(1000);
    throw new Exception("Error");
}
public async Task CallAsync()
{
    try
    {
        await ThrowAsync();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message); // 輸出 "Error"
    }
}

5.2 狀態(tài)機(jī)中的異常處理

狀態(tài)機(jī)的MoveNext方法包含try-catch塊,捕獲異常并通過(guò)builder.SetException設(shè)置到Task中,如前述偽代碼所示。

5.3 聚合異常

如果一個(gè)Task等待多個(gè)子任務(wù)(如Task.WhenAll),可能會(huì)拋出AggregateException,包含所有子任務(wù)的異常。await會(huì)自動(dòng)解包,拋出第一個(gè)異常。

6. 自定義Awaiter和擴(kuò)展性

6.1 Awaiter模式

C#支持await任何實(shí)現(xiàn)了awaiter模式的類(lèi)型,要求:

  • 提供GetAwaiter方法,返回一個(gè)awaiter對(duì)象。
  • awaiter實(shí)現(xiàn)INotifyCompletion(或ICriticalNotifyCompletion),并提供:
    • bool IsCompleted:指示任務(wù)是否完成。
    • GetResult:獲取結(jié)果或拋出異常。

6.2 自定義Awaiter的用途

例如,ValueTask<T>是一個(gè)輕量級(jí)替代Task<T>的結(jié)構(gòu),用于高頻調(diào)用場(chǎng)景減少內(nèi)存分配:

public ValueTask<int> ComputeValueAsync()
{
    return new ValueTask<int>(42); // 同步完成,無(wú)需分配Task
}

7. 實(shí)際應(yīng)用與示例分析

7.1 異步方法的編寫(xiě)

編寫(xiě)異步方法的最佳實(shí)踐:

  • 使用async Taskasync Task<T>作為返回類(lèi)型。
  • 避免async void,除非是事件處理程序。
  • 在非UI代碼中使用ConfigureAwait(false)

7.2 異步流(C# 8.0+)

異步流(IAsyncEnumerable<T>)允許異步生成和消費(fèi)數(shù)據(jù)序列:

public async IAsyncEnumerable<int> GenerateNumbersAsync()
{
    for (int i = 0; i < 5; i++)
    {
        await Task.Delay(100);
        yield return i;
    }
}
await foreach (var number in GenerateNumbersAsync())
{
    Console.WriteLine(number);
}

8. 總結(jié)與實(shí)踐建議

C#的異步編程通過(guò)asyncawait,結(jié)合狀態(tài)機(jī)、任務(wù)調(diào)度和線程管理,實(shí)現(xiàn)了高效的非阻塞代碼。其底層原理包括:

  • 狀態(tài)機(jī):編譯器將異步方法轉(zhuǎn)換為狀態(tài)機(jī),管理暫停和恢復(fù)。
  • Task:表示異步操作,由任務(wù)調(diào)度器和線程池執(zhí)行。
  • 上下文:同步上下文和執(zhí)行上下文確保線程安全性。
  • 異常處理:異常在Task中傳播,await時(shí)重新拋出。

實(shí)踐建議

  • 使用ConfigureAwait(false)優(yōu)化服務(wù)器端性能。
  • 確保異常在合適的地方被捕獲和處理。
  • 將CPU-bound任務(wù)調(diào)度到線程池,避免阻塞UI線程。
  • 利用異步流處理大數(shù)據(jù)或?qū)崟r(shí)數(shù)據(jù)。

通過(guò)理解這些底層機(jī)制,有助于我們更高效地編寫(xiě)異步代碼,從而構(gòu)建高性能、可伸縮的應(yīng)用程序。

?轉(zhuǎn)自https://www.cnblogs.com/code-daily/p/18909634


該文章在 2025/6/11 9:36:30 編輯過(guò)
關(guān)鍵字查詢(xún)
相關(guān)文章
正在查詢(xún)...
點(diǎn)晴ERP是一款針對(duì)中小制造業(yè)的專(zhuān)業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國(guó)內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對(duì)港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場(chǎng)、車(chē)隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場(chǎng)作業(yè)而開(kāi)發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類(lèi)企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉(cāng)儲(chǔ)管理系統(tǒng)提供了貨物產(chǎn)品管理,銷(xiāo)售管理,采購(gòu)管理,倉(cāng)儲(chǔ)管理,倉(cāng)庫(kù)管理,保質(zhì)期管理,貨位管理,庫(kù)位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號(hào)管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶(hù)的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved

熟女人妻AV五十路六十路app| 日韩女同一区二区三区在线播放 | 天天操人人操天天| 最真实国产夫妻性生活一级| 亚洲尤物Tv| 国产 日韩欧美在线观看| 久久一级黄色电影片| 久久久久久久久调教亚洲| 欧美自拍三区| 粉嫩人妻不卡| 亚洲少妇综合久久| 经典三级AV 一区| 久久久久久久久久三级电影大全| 国产欧美久久久精品在线观看| 97se狠狠狠综合亚洲狠狠| 老@熟妇av| 毛片男人27黑毛女人19| 台湾佬偷拍一区二区| 毛片在线999| 中文字幕热不卡午夜| 欧美性爱色吧视频在线观看| 偷不卡国产| 国产精品久久久久久电影| 欧美成人一级网址| 日本黄色不卡免费在线观看欧美你别 | 久久99视频小少妇| 欧美人妻七区| 国产怡红院视频在线观看| 婷婷五月激情欧美网| 精品奥美一区二区三区| 免费视频艹B| 骚妇视频偷拍| 亚洲日韩欧美一区色| 婷婷五月天丝袜美腿视频网站| 色吊丝国产| 美女性爱在线| 午夜av资讯天堂| 久久国产wwww| 国产原创亚洲精品| 日本黄色一本二本| 精品在线九区|