iT邦幫忙

2025 iThome 鐵人賽

DAY 24
0

async/await 降糖展開(狀態機 IL 分析)

目標

快速理解一個 async/await 方法被編譯後的「狀態機 + builder + awaiter」實際樣貌,並透過 C# 反編譯與 IL 片段觀察控制流程、例外、同步快速路徑與延續安排。

範例原始方法(語法糖前)

public static async Task<int> FetchAndParseAsync(HttpClient http, string url)
{
    var html = await http.GetStringAsync(url);          // await #1
    await Task.Delay(10);                                // await #2
    return html.Length;
}

編譯後概念性展開(簡化版)

[CompilerGenerated]
private sealed class <FetchAndParseAsync>d__0 : IAsyncStateMachine
{
    public int <>1__state;
    public AsyncTaskMethodBuilder<int> <>t__builder;

    // 參數捕捉
    public HttpClient http;
    public string url;

    // 局部變數提升
    private string <html>5__2;

    // awaiter 暫存
    private TaskAwaiter<string> <>u__1;
    private TaskAwaiter <>u__2;

    void IAsyncStateMachine.MoveNext()
    {
        int result;
        try
        {
            TaskAwaiter<string> a1;
            TaskAwaiter a2;

            switch (<>1__state)
            {
                case -1: // 初始
                    a1 = http.GetStringAsync(url).GetAwaiter();
                    if (!a1.IsCompleted)
                    {
                        <>1__state = 0;
                        <>u__1 = a1;
                        <>t__builder.AwaitUnsafeOnCompleted(ref a1, ref this);
                        return;
                    }
                    goto COMPLETE_AWAIT1;

                case 0: // 從 await #1 回來
                    a1 = <>u__1;
                    <>u__1 = default;
                    <>1__state = -1;
                    goto COMPLETE_AWAIT1;

                case 1: // 從 await #2 回來
                    a2 = <>u__2;
                    <>u__2 = default;
                    <>1__state = -1;
                    goto COMPLETE_AWAIT2;
            }

        COMPLETE_AWAIT1:
            var html = a1.GetResult();
            <html>5__2 = html;

            a2 = Task.Delay(10).GetAwaiter();
            if (!a2.IsCompleted)
            {
                <>1__state = 1;
                <>u__2 = a2;
                <>t__builder.AwaitUnsafeOnCompleted(ref a2, ref this);
                return;
            }

        COMPLETE_AWAIT2:
            a2.GetResult(); // 確認完成 / 傳播例外
            result = <html>5__2.Length;
        }
        catch (Exception ex)
        {
            <>1__state = -2;
            <>t__builder.SetException(ex);
            return;
        }

        <>1__state = -2;
        <>t__builder.SetResult(result);
    }

    void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine) =>
        <>t__builder.SetStateMachine(stateMachine);
}

public static Task<int> FetchAndParseAsync(HttpClient http, string url)
{
    var sm = new <FetchAndParseAsync>d__0
    {
        <>1__state = -1,
        <>t__builder = AsyncTaskMethodBuilder<int>.Create(),
        http = http,
        url = url
    };
    sm.<>t__builder.Start(ref sm);
    return sm.<>t__builder.Task;
}

重點:

  • <>1__state = -1 初始;0 / 1 對應各 await 之「掛起後返回」續點。
  • 每個 await 轉成:取 awaiter → 判斷 IsCompleted → 未完成則:儲存 state + AwaitUnsafeOnCompleted + return。
  • 回復後用 switch 進續點;GetResult() 取值或拋出例外。
  • SetResult / SetException 結束任務。

上一篇
ValueTask 提高高同步命中率
下一篇
IL 對應 await
系列文
新 .NET & Azure & IoT & AI 開源技術實戰手冊 (含深入官方程式碼講解) 25
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言