[英]What happens when you await a failed task
我有一個理論問題要問你。 如果我在另一個任務中等待任務的結果會怎樣? 我想知道我當前的系統以后是否可以工作。
一個任務被啟動並做一些事情。 在某些時候,該任務可能需要另一個任務來處理當前任務無法自行處理的數據。 所以我使用 await 來確保當前任務不會繼續,只要他沒有幫助任務的結果。 但是如果 helper 失敗了會發生什么? 當前任務會保持鎖定狀態嗎?
我能以某種方式避免這種死鎖嗎(不改變系統本身 - 任務內的任務)?
一個任務被啟動並做一些事情。 在某些時候,該任務可能需要另一個任務來處理當前任務無法自行處理的數據。 所以我使用 await 來確保當前任務不會繼續,只要他沒有幫助任務的結果。 但是如果 helper 失敗了會發生什么? 當前任務會保持鎖定狀態嗎?
async
和await
背后的核心思想是異步代碼的工作方式與同步代碼幾乎相同。
所以,如果你有這樣的同步代碼:
void HelperMethod()
{
throw new InvalidOperationException("test");
}
void DoStuff()
{
HelperMethod();
}
那么您會期望DoStuff
從輔助方法傳播InvalidOperationException
。 同樣,這就是異步代碼會發生的情況:
async Task HelperMethodAsync()
{
throw new InvalidOperationException("test");
}
async Task DoStuffAsync()
{
await HelperMethodAsync();
}
也就是說, DoStuffAsync
也將傳播InvalidOperationException
。
現在,它的工作方式當然不完全相同,因為它必須是異步的,但一般的想法是,所有的控制流,例如try
/ catch
、 for
循環等,都“僅適用於”異步代碼非常類似於同步代碼。
實際發生的是,當HelperMethod
以InvalidOperationException
結束時,異常被捕獲並放置在返回的Task
,任務完成。 當DoStuffAsync
的await
看到任務已完成時,它會檢查其異常並重新引發第一個異常(在這種情況下,只有一個InvalidOperationException
)。 它以一種保留異常調用堆棧的方式重新引發它。 這反過來會導致從DoStuffAsync
返回的Task
以相同的異常完成。
因此,在async
和await
做了一些工作,以確保您可以使用await
調用其他方法,並像在同步代碼中一樣使用try
/ catch
。 但大多數時候你不必意識到這一點。
這真的很容易測試。 例如:
[TestMethod, ExpectedException(typeof(Exception))]
public async Task DoFaultedTaskThrowOnAwait()
{
var task = Task.Factory.StartNew(() => { throw new Exception("Error 42"); });
await task;
}
[TestMethod, ExpectedException(typeof(AggregateException))]
public void DoFaultedTaskThrowOnWait()
{
var task = Task.Factory.StartNew(() => { throw new Exception("Error 42"); });
task.Wait();
}
兩個測試都通過了,請注意Wait
會拋出一個AggregateException
,而await
會拋出Exception
。
如果我在另一個任務中等待任務的結果會怎樣?
你只能await
一個Task.Result
,如果它是一個awaitable
(這意味着它有一個GetAwaiter
方法)。 這種情況很少見。 我假設您的意思是await
內部任務。
但是如果 helper 失敗了會發生什么? 當前任務會保持鎖定狀態嗎?
首先,我不確定您所說的“鎖定”是什么意思。 當您await
內部任務時,該任務不會被鎖定。 控制權返回給調用方法,直到該內部任務完成。 如果該內部任務失敗並且您未能正確處理該異常,則您的父任務也會出錯。 您需要確保優雅地處理異常:
var task =
Task.Run(async () =>
{
try
{
await AsyncHelper.DoSomethingAsync();
}
catch (Exception e)
{
// Handle exception gracefully
}
});
如果您await
父任務,您會注意到從未處理的內部任務傳播的內部異常。
我可以以某種方式避免這種僵局嗎?
在這種特定情況下,我認為您的代碼沒有理由死鎖。 不知道為什么這讓你擔心。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.