Task中的ConfigureAwait

獠牙發表於2024-06-13

一、ConfigureAwait的作用
ConfigureAwait方法是Task類中的一個例項方法,它用於配置任務的執行上下文。執行上下文指的是任務在執行期間所處的環境,包括執行緒、同步上下文等。ConfigureAwait方法接受一個布林值引數,用於決定是否捕獲上下文。當引數為true時,表示任務會在之前的上下文中繼續執行。當引數為false時,表示任務會在不同的上下文中執行。 ConfigureAwait方法的原理是透過設定Task物件的一個內部狀態來實現的。當呼叫ConfigureAwait方法時,會建立一個新的Task物件,並將原始Task物件的狀態複製給該新的Task物件。新的Task物件會在執行時,根據引數值決定是否將上下文捕獲。

通俗的講,ConfigureAwait可以取決任務之後的程式碼是繼續返回主執行緒執行還是在新開的執行緒中繼續執行。

二、程式碼示例
ConfigureAwait在介面中應用最明顯:

private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show($"開始執行,ThreadId:{Thread.CurrentThread.ManagedThreadId}", "button1_Click");
Test();
MessageBox.Show($"執行結束,ThreadId:{Thread.CurrentThread.ManagedThreadId}", "button1_Click");
}

public static void Test()
{
var task = XXXAsync(); // 開啟非同步任務,比如下載某個資源
var resuslt = task.Result; // 獲取非同步任務的結果顯示給使用者,這裡會阻塞當前ui執行緒直到非同步執行緒返回結果
MessageBox.Show($"XXXAsync執行結束顯示非同步任務結果:{resuslt},ThreadId:{Thread.CurrentThread.ManagedThreadId}", "Test");
}

private static async Task<string> XXXAsync()
{
await Task.Delay(1000); // 這裡會導致死鎖
//await Task.Delay(1000).ConfigureAwait(false); // 這樣就不會死鎖

MessageBox.Show($"XXXAsync執行結束,ThreadId:{Thread.CurrentThread.ManagedThreadId}", "XXXAsync");

return "XXXAsync.Result";
}
async /await 出現時var resuslt = task.Result會等待任務執行,直到XXXAsync()有返回結果才會繼續執行主執行緒也就是var resuslt = task.Result在主執行緒中掛起,一直佔用主執行緒,但await任務後 MessageBox.Show($"XXXAsync執行結束,ThreadId:{Thread.CurrentThread.ManagedThreadId}", "XXXAsync");程式碼是在同步執行,是在主執行緒上進行,由於主執行緒被var resuslt = task.Result一直佔用,await程式碼就會無法在主執行緒上執行,出現卡死現象。

ConfigureAwait則會解決該問題,當ConfigureAwait(true)時,則是返回主執行緒執行await後續程式碼,也是預設情況出現卡死,ConfigureAwait(false)時就會解決該問題,await後的程式碼會在支執行緒繼續執行,不會出現該問題。

注意: async /await 返回為task與var resuslt = task.Result連用時,await後的任務ConfigureAwait的屬性設定為false避免假死。

在非介面程式碼上進行測試:

static void Main(string[] args)
{
Console.WriteLine("開始執行程式");
Console.WriteLine("這是主函式:{0}", Thread.CurrentThread.ManagedThreadId);
var task = tt();
var result = task.Result;
Console.WriteLine("執行結果為:"+result+" "+ Thread.CurrentThread.ManagedThreadId);
Console.Read();

}
public static async Task<string> tt()
{
await Task.Run(() =>
{
Console.WriteLine("這是等待方法非同步執行緒:{0}", Thread.CurrentThread.ManagedThreadId);
}).ConfigureAwait(true);
Console.WriteLine("這是非同步方法剩餘內容:{0}", Thread.CurrentThread.ManagedThreadId);
return "非同步方法完成";
}

await後續程式碼並沒有返回主執行緒執行,而是直接在支執行緒執行,並沒有出現卡死的情況。猜想或許只有在介面操作時才會出現假死情況!在後續中也會繼續留意該問題!
————————————————

版權宣告:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連結和本宣告。

原文連結:https://blog.csdn.net/qiaodahua/article/details/134116136

相關文章