详解.NET 异步编程,如何透过现象,看async/await本质

Posted DotNET技术圈

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了详解.NET 异步编程,如何透过现象,看async/await本质相关的知识,希望对你有一定的参考价值。

前言

博客园中有很多关于 .NET async/await 的介绍,但是很遗憾,很少有正确的,甚至说大多都是“从现象编原理”都不过分。

最典型的比如通过前后线程 ID 来推断其工作方式、在 async 方法中用 Thread.Sleep 来解释 Task 机制而导出多线程模型的结论、在 Task.Run 中包含 IO bound 任务来推出这是开了一个多线程在执行任务的结论等等。

看上去似乎可以解释的通,可是很遗憾,无论是从原理还是结论上看都是错误的。

要了解 .NET 中的 async/await 机制,首先需要有操作系统原理的基础,否则的话是很难理解清楚的,如果没有这些基础而试图向他人解释,大多也只是基于现象得到的错误猜想。

初看异步

说到异步大家应该都很熟悉了,2012 年 C# 5 引入了新的异步机制:Task,并且还有两个新的关键字 await 和 async,这已经不是什么新鲜事了,而且如今这个异步机制已经被各大语言借鉴,如 javascript、TypeScript、Rust、C++ 等等。

下面给出一个简单的对照:

语言 调度单位 关键字/方法
C# Task<>ValueTask<> asyncawait
C++ std::future<> co_await
Rust std::future::Future<> .await
JavaScript、TypeScript Promise<> asyncawait

当然,这里这并不是本文的重点,只是提一下,方便大家在有其他语言经验的情况下(如果有),可以认识到 C# 中 Task 和 async/await 究竟是一个和什么可以相提并论的东西。

多线程编程

在该异步编程模型诞生之前,多线程编程模型是很多人所熟知的。一般来说,开发者会使用 Threadstd::thread 之类的东西作为线程的调度单位来进行多线程开发,每一个这样的结构表示一个对等线程,线程之间采用互斥或者信号量等方式进行同步。

多线程对于科学计算速度提升等方面效果显著,但是对于 IO 负荷的任务,例如从读取文件或者 TCP 流,大多数方案只是分配一个线程进行读取,读取过程中阻塞该线程:

 
   
   
 
Copy

以上是关于详解.NET 异步编程,如何透过现象,看async/await本质的主要内容,如果未能解决你的问题,请参考以下文章

异步编程待看文章

async 和await

C# Async与Await的使用

如何正确理解.NET 4.5和C#5.0中的async/await异步编程模式

.NET4.5新特性之异步编程(Async和Await)的使用

Spring Boot中异步线程池@Async详解