.NET 6 新特性 WaitAsync

Intro

在 .NET 6 里新增加了一个 WaitAsync 的方法,用来异步地等待一个任务完成,异步等待的时候可以指定一个 Timeout 时间或者一个取消令牌 CancellationToken,在之前的版本中只有一个同步的 Wait 会等待任务的完成,不支持比较好的任务超时或取消处理,如果要实现的话要自己写扩展,很多开源项目甚至微软的项目里会有一个 TimeoutAfter 之类的扩展方法,有了 WaitAsync 之后就可以取代这些扩展了

Definition

新加的 WaitAsync 是一个扩展方法,定义如下:

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 的一个示例,当 Timeout 时间到了之后 Task 还没完成就会 throw 一个 TimeoutException,但是并不会影响原来的任务继续执行,除非自己能够在 exception 的时候将原来的 Task 给中止,上面示例的输出结果如下:

TimeoutException
WaitingForActivation,WaitingForActivation,WaitingForActivation
WaitingForActivation
RanToCompletion,RanToCompletion,RanToCompletion
RanToCompletion

可以看到,即使发生了 Timeout 也不会影响原来 Task 的执行

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);

输出结果如下:

Task cancelled
RanToCompletion,WaitingForActivation,WaitingForActivation
WaitingForActivation
RanToCompletion,RanToCompletion,RanToCompletion
RanToCompletion

使用 CancellationToken 的时候抛出的异常是  TaskCanceledException,而不是前面的 TimeoutException

而抛异常的行为和前面一样,并不会影响原来 Task 的状态

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);
}

输出结果如下:

TimeoutException
TaskCanceledException

可以看出来哪一个条件 WaitAsync 的条件先满足,抛出的就是哪一个对应的异常,两个异常都没有的就可以正常结束

More

WaitAsync 方法可以解决很多需要等待或者设置 Timeout 的场景,官方支持了这个 API 以后很多 TimeoutAfter/WithCancellationToken 之类的扩展方法可以去掉了

WaitAsync 抛出的异常需要针对处理,如果是 Timeout 则是 TimeoutException 如果是 CancellationToken Cancel 引发的异常则是 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

.NET 6 新特性 WaitAsync相关推荐

  1. .NET 6 新特性 Parallel ForEachAsync

    .NET 6 新特性 Parallel ForEachAsync Intro 在 .NET 6 中有一个 API Parallel.ForEachAsync 在官方的博客中一直被忽略,但是我觉得这个 ...

  2. 我要学ASP.NET MVC 3.0(一): MVC 3.0 的新特性

    摘要 MVC经过其1.0和2.0版本的发展,现在已经到了3.0的领军时代,随着技术的不断改进,MVC也越来越成熟.使开发也变得简洁人性化艺术化. 园子里有很多大鸟都对MVC了如指掌,面对问题犹同孙悟空 ...

  3. .NET 4.0 Interop新特性ICustomQueryInterface (转载)

    .NET 4.0 Interop新特性ICustomQueryInterface 在.NET Framework v4.0发布的新功能中,在名字空间System.Runtime.InteropServ ...

  4. oracle如何查询虚拟列,Oracle11g新特性之--虚拟列(VirtualColumn)

    Oracle 11g新特性之--虚拟列(Virtual Column) Oracle 11G虚拟列Virtual Column介绍 在老的 Oracle 版本,当我们需要使用表达式或者一些计算公式时, ...

  5. mysql8导入 psc 没有数据_新特性解读 | MySQL 8.0.22 任意格式数据导入

    作者:杨涛涛 资深数据库专家,专研 MySQL 十余年.擅长 MySQL.PostgreSQL.MongoDB 等开源数据库相关的备份恢复.SQL 调优.监控运维.高可用架构设计等.目前任职于爱可生, ...

  6. mysql query browswer_MySQL数据库新特性之存储过程入门教程

    MySQL数据库新特性之存储过程入门教程 在MySQL 5中,终于引入了存储过程这一新特性,这将大大增强MYSQL的数据库处理能力.在本文中将指导读者快速掌握MySQL 5的存储过程的基本知识,带领用 ...

  7. windows无法配置此无线连接_Kubernetes 1.18功能详解:OIDC发现、Windows节点支持,还有哪些新特性值得期待?...

    Kubernetes 1.18发布,一些对社区产生影响的新特性日渐完善,如 KSA(Kubernetes Service Account) tokens的OIDC发现和对Windows节点的支持.在A ...

  8. java字符串去重复_Java 8新特性:字符串去重

    本文首发与InfoQ. 8月19日,Oracle发布了JDK 8u20,JDK 8u20包含很多新特性,比如Java编译器更新.支持在运行时通过API来修改MinHeapFreeRatio和MaxHe ...

  9. Oracle 11g 新特性 -- Transparent Data Encryption (透明数据加密TDE) 增强 说明

    一.TransparentData Encryption (TDE:透明数据加密) 说明 Orace TDE 是Orcle 10R2中的一个新特性,其可以用来加密数据文件里的数据,保护从操作系统层面上 ...

最新文章

  1. linux open系统调用的O_DIRECT标记
  2. 【java】异常的分类
  3. 深度 | 智慧•城市,基于国际视野下的思考
  4. python拼接mysql时遇到unsupported format character ‘?‘ “(0x82f1)“
  5. centos8下重启网卡命令_centos8 网络配置
  6. 能玩java游戏oppo按键手机_游戏手机排行榜|OPPO Reno果然不负期待
  7. 数字时钟设计verilog_数字IC设计基本概念之创建时钟
  8. python visual studio pandas_pandas DataFrame索引行列的实现
  9. (131)FPGA面试题-用波形图表示D触发器的功能
  10. 全面综述:基于3D骨架的深度学习行为识别方法
  11. python全套视频免费教程_《python免费视频教程33》 请问谁有靠谱的Python全套视频教程,求推荐分享...
  12. 架构师的“功夫在诗外”之二
  13. iOS13 微信消息不通知 打开微信才能看到消息
  14. allure的安装使用以及报告的生成
  15. 英飞凌XC2000系列单片机FLASH加解密策略
  16. Java LPT,使用Java对LPT端口进行编程。真?
  17. 三星S7 Edge怎么打开usb调试呢
  18. Azkaban重新编译,解决:Could not connect to SMTP host: smtp.163.com, port: 465【2022年01月10日】
  19. 【动态规划】买卖股票
  20. anthony1314的数论小基础

热门文章

  1. Java 和 Android系统环境变量设置
  2. 如何得到所有可视化窗口的句柄?
  3. Spring实战Day2
  4. 设置第三方的SMTP服务
  5. solr5.5索引mysql数据(新手总结)
  6. 【转】基于 Android NDK 的学习之旅-----数据传输(引用数据类型)
  7. Mysql中explain命令查看语句执行概况
  8. WCF中使用控件的委托,线程中的UI委托
  9. hdu 1460 完数
  10. 每日一小练——按字典顺序列出全部子集