[英]Try/catch not catching error in unawaited async task within WebAPI DelegatingHandler
[英]Async method blocking on unawaited task
在我當前的項目中,我有一段代碼,在將其簡化到遇到問題的地方之后,看起來像這樣:
private async Task RunAsync(CancellationToken cancel)
{
bool finished = false;
while (!cancel.IsCancellationRequested && !finished)
finished = await FakeTask();
}
private Task<bool> FakeTask()
{
return Task.FromResult(false);
}
如果我不等待就使用此代碼,無論如何我最終都會阻塞:
// example 1
var task = RunAsync(cancel); // Code blocks here...
... // Other code that could run while RunAsync is doing its thing, but is forced to wait
await task;
// example 2
var task = RunAsync(cancelSource.Token); // Code blocks here...
cancelSource.Cancel(); // Never called
在實際的項目中,我實際上並沒有使用FakeTask,通常會在其中等待一些Task.Delay,因此大部分時間代碼實際上並沒有阻塞,或者僅進行了有限的迭代。
但是,在單元測試中,我使用的模擬對象執行FakeTask的大部分工作,因此,當我想查看RunAsync是否響應其CancellationToken取消了按我期望的方式取消時,我陷入了困境。
我發現我可以通過await Task.Delay(1)
的頂部添加例如await Task.Delay(1)
來解決此問題,以強制其真正以異步方式運行,但這感覺有些棘手。 有更好的選擇嗎?
您對await
工作有不正確的心理印象。 await
的含義是:
在您的程序中,等待的“偽造”總是完整的,因此協程永遠不會掛起。
有更好的選擇嗎?
如果您的控制流邏輯要求您暫停協程,則使用Task.Yield
。
Task.FromResult
實際上實際上是同步運行的,就像await Task.Delay(0)
。 如果要實際模擬異步代碼,請調用Task.Yield()
。 這將創建一個等待的任務,等待時異步地返回當前上下文。
正如@SLaks所說,您的代碼將同步運行。 一件事正在運行異步代碼,而另一件事正在運行並行代碼。
如果需要並行運行代碼,則可以使用Task.Run
。
class Program
{
static async Task Main(string[] args)
{
var tcs = new CancellationTokenSource();
var task = Task.Run(() => RunAsync("1", tcs.Token));
var task2 = Task.Run(() => RunAsync("2", tcs.Token));
await Task.Delay(1000);
tcs.Cancel();
Console.ReadLine();
}
private static async Task RunAsync(string source, CancellationToken cancel)
{
bool finished = false;
while (!cancel.IsCancellationRequested && !finished)
finished = await FakeTask(source);
}
private static Task<bool> FakeTask(string source)
{
Console.WriteLine(source);
return Task.FromResult(false);
}
}
C#的異步方法同步執行,直到必須等待結果為止。
在您的示例中,沒有方法必須等待結果的地方,因此循環將永遠運行,從而阻塞了調用者。
插入一個等待Task.Yield()以模擬一些實際的異步工作應該會有所幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.