王剑编程网

分享专业编程知识与实战技巧

C#语言学习笔记13 —— 异步编程 async/await 初步

异步编程 async/await 初步

async/await 简介

异步方法的主要应用场景:(1)计算密集型(2) I/O 密集型

异步编程能提升网络服务器的吞吐量,提高用户界面的响应性。

C# 直接在语言层面上支持异步编程,它使用 async/await 语法,在 Task asynchronous programming (TAP) 模型上实现了多线程编程。

使用 async/await 编写异步代码时,形式上与同步代码差不多,无需分心编写通常重复的线程管理代码,因而能更专注于业务逻辑。

由于形式简单,它降低了编写多线程代码的负担,减少出错几率,提高了编码效率。

同步代码与异步代码比较

例如,一个基本串流拷贝操作,看一下它的同步版本与异步版本在代码实现形式上有什么不同:

从代码可以看出,异步版本函数把返回类型void,改成 async Task,在同步方法调用前面加入 await,并换成了异步方法, 这样就可以实现异步功能,是不是很简单?

从代码阅读角度来讲,同步版本和异步版本流程是基本一致的,它符合人的思维习惯,也很容易理解。

在异步版本中,async 用来说明该函数是一个异步函数。如果函数没有返回值,则返回 Task; 如果函数需要返回 TResult,则返回Task<TResult>。 函数里面在需要等待异步代码完成的地方,加上 await 关键字,表示要等待它完成后再继续。 根据需要,可以加入更多的同步代码,加入多个 await 来等待其它异步代码。

C# 编译器会特殊处理异步函数,为它生成依赖 Task 机制的代码,在 DotNet 自身的多线程支持环境下,完成多线程之间的协作,保证代码按照指定的方式正确运行。

异步 IO 例子

我们来看一个访问网络资源的例子:

计算密集型例子

耗时的 CPU 计算任务可以放到 Task.Run() 来执行,避免阻塞当前线程。

下面例子功能为:计算指定数字以内的所有质数的个数。例子里面使用 Stopwatch 类来评估运行所用的时间。

异步操作的异常处理

await 可以捕获到异步操作里抛出的异常。

下面这个例子展示:如果文件不存在,将会显示出错误信息;如果碰到其它类型错误,也会显示出来。

异步操作的中途取消

可以使用一个 CancellationTokenSource 实例来取消多个任务。

CancellationTokenSource 提供了 Token 属性,类型为 CancellationToken,作为参数传给异步任务。

可以调用 CancellationTokenSource 的 Cancel() 方法来设置 CancellationToken 的状态。

异步任务根据 CancellationToken 的状态来控制自己的执行。

下面是一个加入取消功能的计算质数个数的例子:

不取消时的输出类似为:

中途按键盘 “C” 键取消任务时的输出类似为:

异步操作的返回类型

异步操作支持多种返回类型:

  • Task,对应方法不需要返回值,即 void
  • Task<TResult>,对应方法返回 TResult
  • void,对应事件处理函数
  • 返回类型有可访问的 GetAwaiter 方法
  • IAsyncEnumerable<T>,对应方法返回一个异步流

下面是一个返回 IAsyncEnumerable<T> 的例子,可以用 await foreach 语句来消费异步流。

结束语

C# 的 async/await 语法简化了异步编程模型,它是在 DotNet 的 Task 机制上实现的,在使用过程中,往往也会用到 Task 的各种方法。

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言