.NET 6 新特性 WaitAsync
.NET 6 新特性 WaitAsync
Intro
在 .NET 6 里新增加了一個 WaitAsync 的方法,用來異步地等待一個任務(wù)完成,異步等待的時候可以指定一個 Timeout 時間或者一個取消令牌 CancellationToken,在之前的版本中只有一個同步的 Wait 會等待任務(wù)的完成,不支持比較好的任務(wù)超時或取消處理,如果要實(shí)現(xiàn)的話要自己寫擴(kuò)展,很多開源項(xiàng)目甚至微軟的項(xiàng)目里會有一個 TimeoutAfter 之類的擴(kuò)展方法,有了 WaitAsync 之后就可以取代這些擴(kuò)展了
Definition
新加的 WaitAsync 是一個擴(kuò)展方法,定義如下:
public?static?Task?WaitAsync(this?Task?task,?TimeSpan?timeout); public?static?Task?WaitAsync(this?Task?task,?CancellationToken?cancellationToken); public?static?Task?WaitAsync(this?Task?task,?TimeSpan?timeout,?CancellationToken?cancellationToken); //?泛型版本 public?static?Task<TResult>?WaitAsync<TResult>(this?Task<TResult>?task,?TimeSpan?timeout); public?static?Task<TResult>?WaitAsync<TResult>(this?Task<TResult>?task,?CancellationToken?cancellationToken); public?static?Task<TResult>?WaitAsync<TResult>(this?Task<TResult>?task,?TimeSpan?timeout,?CancellationToken?cancellationToken);Timeout Sample
來看一個 WaitAsync Timeout 的 使用示例:
var?tasks?=?new?List<Task>(); tasks.AddRange(new[]? {?Task.Delay(TimeSpan.FromSeconds(5)),Task.Delay(TimeSpan.FromSeconds(8)),Task.Delay(TimeSpan.FromSeconds(6)) }); Task?task?=?Task.WhenAll(tasks); try {await?task.WaitAsync(TimeSpan.FromSeconds(3)); } catch?(TimeoutException) {Console.WriteLine(nameof(TimeoutException)); } finally {Console.WriteLine(string.Join(",",?tasks.Select(t?=>?t.Status.ToString())));Console.WriteLine(task.Status); }await?Task.Delay(TimeSpan.FromSeconds(5)); Console.WriteLine(string.Join(",",?tasks.Select(t?=>?t.Status.ToString()))); Console.WriteLine(task.Status);上面是一個使用 Timeout 的一個示例,當(dāng) Timeout 時間到了之后 Task 還沒完成就會 throw 一個 TimeoutException,但是并不會影響原來的任務(wù)繼續(xù)執(zhí)行,除非自己能夠在 exception 的時候?qū)⒃瓉淼?Task 給中止,上面示例的輸出結(jié)果如下:
TimeoutException WaitingForActivation,WaitingForActivation,WaitingForActivation WaitingForActivation RanToCompletion,RanToCompletion,RanToCompletion RanToCompletion可以看到,即使發(fā)生了 Timeout 也不會影響原來 Task 的執(zhí)行
Cancellation Sample
接著來看一下 CancellationToken 的使用示例
var?cts?=?new?CancellationTokenSource(); var?tasks?=?new?List<Task>(); tasks.AddRange(new[] {Task.Delay(TimeSpan.FromSeconds(4)),Task.Delay(TimeSpan.FromSeconds(8)),Task.Delay(TimeSpan.FromSeconds(6)) }); var?task?=?Task.WhenAll(tasks); try {cts.CancelAfter(TimeSpan.FromSeconds(5));await?task.WaitAsync(cts.Token); } catch?(TaskCanceledException) {Console.WriteLine("Task?cancelled"); } finally {Console.WriteLine(string.Join(",",?tasks.Select(t?=>?t.Status.ToString())));Console.WriteLine(task.Status); }await?Task.Delay(TimeSpan.FromSeconds(5)); Console.WriteLine(string.Join(",",?tasks.Select(t?=>?t.Status.ToString()))); Console.WriteLine(task.Status);輸出結(jié)果如下:
Task?cancelled RanToCompletion,WaitingForActivation,WaitingForActivation WaitingForActivation RanToCompletion,RanToCompletion,RanToCompletion RanToCompletion使用 CancellationToken 的時候拋出的異常是 ?TaskCanceledException,而不是前面的 TimeoutException
而拋異常的行為和前面一樣,并不會影響原來 Task 的狀態(tài)
Another Sample
我們再來看一個既使用 Timeout 又使用取消令牌的一個示例吧
try {await?Task.Delay(TimeSpan.FromSeconds(5)).WaitAsync(TimeSpan.FromSeconds(3),?CancellationToken.None); } catch(Exception?ex) {Console.WriteLine(ex.GetType().Name); }try {using?var?cancellationTokenSource?=?new?CancellationTokenSource();cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(2));await?Task.Delay(TimeSpan.FromSeconds(5)).WaitAsync(TimeSpan.FromSeconds(10),?cancellationTokenSource.Token); } catch(Exception?ex) {Console.WriteLine(ex.GetType().Name); }輸出結(jié)果如下:
TimeoutException TaskCanceledException可以看出來哪一個條件 WaitAsync 的條件先滿足,拋出的就是哪一個對應(yīng)的異常,兩個異常都沒有的就可以正常結(jié)束
More
WaitAsync 方法可以解決很多需要等待或者設(shè)置 Timeout 的場景,官方支持了這個 API 以后很多 TimeoutAfter/WithCancellationToken 之類的擴(kuò)展方法可以去掉了
WaitAsync 拋出的異常需要針對處理,如果是 Timeout 則是 TimeoutException 如果是 CancellationToken Cancel 引發(fā)的異常則是 TaskCanceledException
References
https://github.com/dotnet/runtime/pull/48842
https://github.com/dotnet/runtime/blob/v6.0.0-preview.7.21377.19/src/libraries/Common/tests/System/Threading/Tasks/TaskTimeoutExtensions.cs
https://github.com/WeihanLi/SamplesInPractice/blob/master/net6sample/WaitAsyncSample/Program.cs
總結(jié)
以上是生活随笔為你收集整理的.NET 6 新特性 WaitAsync的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 依赖注入生命周期
- 下一篇: Blazor+Dapr+K8s微服务之服