簡體   English   中英

當您等待失敗的任務時會發生什么

[英]What happens when you await a failed task

我有一個理論問題要問你。 如果我在另一個任務中等待任務的結果會怎樣? 我想知道我當前的系統以后是否可以工作。

一個任務被啟動並做一些事情。 在某些時候,該任務可能需要另一個任務來處理當前任務無法自行處理的數據。 所以我使用 await 來確保當前任務不會繼續,只要他沒有幫助任務的結果。 但是如果 helper 失敗了會發生什么? 當前任務會保持鎖定狀態嗎?

我能以某種方式避免這種死鎖嗎(不改變系統本身 - 任務內的任務)?

一個任務被啟動並做一些事情。 在某些時候,該任務可能需要另一個任務來處理當前任務無法自行處理的數據。 所以我使用 await 來確保當前任務不會繼續,只要他沒有幫助任務的結果。 但是如果 helper 失敗了會發生什么? 當前任務會保持鎖定狀態嗎?

asyncawait背后的核心思想是異步代碼的工作方式與同步代碼幾乎相同。

所以,如果你有這樣的同步代碼:

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 / catchfor循環等,都“僅適用於”異步代碼非常類似於同步代碼。

實際發生的是,當HelperMethodInvalidOperationException結束時,異常被捕獲並放置在返回的Task ,任務完成。 DoStuffAsyncawait看到任務已完成時,它會檢查其異常並重新引發第一個異常(在這種情況下,只有一個InvalidOperationException )。 它以一種保留異常調用堆棧的方式重新引發它。 這反過來會導致從DoStuffAsync返回的Task以相同的異常完成。

因此,在asyncawait做了一些工作,以確保您可以使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM