翻译 异步I/O不会创建新的线程
异步I/O不会创建新的线程
本文翻译自 Stephen Cleary 的 [There is No Thread] 原文地址 https://blog.stephencleary.com/2013/11/there-is-no-thread.html
这是异步编程最基本的事实 : 异步I/O不会创建新的线程
反对这个事实的人很多,他们对此的看法是 "如果我await一个操作,那么一定会有一个线程正在等待,它可能是一个线程池的线程,或者是操作系统线程,或者是某个设备的驱动程序"
不用关注这些看法, 只需要记住如果异步操作是纯粹的(方法全是async),那么就不会产生新的线程
不过这么一个简单的结论显然并不能够让他们信服,下面就看看异步到底发生了什么
让我们跟踪一个异步操作直到硬件层面,注:Net部分和设备驱动部分将被简化描述 (因为细节太多了)
下面是一个通用的写入操作 (例如 文件、网络、USB面包机等等)
private async void Button_Click(object sender, RoutedEventArgs e)
{
byte[] data = ...
await myDevice.WriteAsync(data, 0, data.Length);
}
我们已经知道在await的时候UI线程不会被阻塞,那么问题来了: 是否是UI线程创建了另外一个线程杀了祭天换来了自己的自由....
关于UI线程是否犯下这一恶行,让我们深入推断一下
首先 : 看看类库 (BCL的代码) 假设 WriteAsync 是使用.Net中标准的异步方式平台调用(P/Invoke)I/O系统,这是一个基于异步方式的I/O,所以这会在设备的底层上启动一个win32异步方式I/O操作句柄
然后操作系统会告诉设备驱动程序进行写操作,代码实现是构造出表示写请求的对象,这个对象称为I/O请求包(IRP)
设备驱动程序接收到IRP后会向设备发出一个命令来写出数据,如果这个设备支持直接内存存取技术(DMA),只需将缓冲区地址写入设备寄存器即可,设备驱动程序能做到将IRP标记为 "pending" 后交把控制权交还操作系统

在这里发现了真相的核心所在 : 在处理IRP时,设备驱动是不允许阻塞的。这意味着如果IRP不能立即完成,那么它必须异步处理,即使对于同步的api也是如此!在设备驱动级别,所有(有意义)的请求都是异步的
引用书籍里的知识 "无论是什么类型的I/O请求,应用程序向驱动程序发出的I/O操作都是异步执行的"
在IRP为 "pending" 时,操作系统返回到类库,类库将未完成的任务返回到应用程序的按钮单击事件方法,该方法挂起async方法,UI线程继续执行
我们已经跟踪请求到系统的尽头 直到物理设备
现在写入操作正在飞快的进行中,有多少个线程正在处理它?
答案是没有
没有设备驱动程序线程、操作系统线程、BCL线程或者写在处理写操作的线程池线程(
翻译 异步I/O不会创建新的线程的更多相关文章
- nodejs中使用worker_threads来创建新的线程
目录 简介 worker_threads isMainThread MessageChannel parentPort和MessagePort markAsUntransferable SHARE_E ...
- 【C++】【MFC】创建新的线程函数
DWORD WINAPI MyThreadProc (LPVOID lpParam){ somestruct* pN = (somestruct*)lpParam; // 将参数转为你的类型 ... ...
- 多线程编程之Windows环境下创建新线程
转自: http://www.cnblogs.com/lgxqf/archive/2009/02/10/1387480.html 在 Win32 API 中,创建线程的基本函数是 CreateThre ...
- Spark无法创建新线程
Spark提交程序报错,无法创建新的线程 原因是因为这台公用机器上跑的进程太多了,需要修改Linux参数,允许用户最大进程数 查看允许用户最大进程数配置 ulimit -a 修改允许用户最大进程数配置 ...
- Java多线程-新特性-线程池
Sun在Java5中,对Java线程的类库做了大量的扩展,其中线程池就是Java5的新特征之一,除了线程池之外,还有很多多线程相关的内容,为多线程的编程带来了极大便利.为了编写高效稳定可靠的多线程程序 ...
- JVM最多能创建多少个线程:unabletocreatenewnativethread
最近需要测试一个长连接服务器,数据上需要达到100W的长连接,测试的客户端,一个线程保持一个连接,发现linux服务器默认创建到3200多个线程的时候,就会报错这个错误“java.lang.OutOf ...
- Spring session(redis存储方式)监听导致创建大量redisMessageListenerContailner-X线程
待解决的问题 Spring session(redis存储方式)监听导致创建大量redisMessageListenerContailner-X线程 解决办法 为spring session添加spr ...
- Linux 循环创建多个线程
这里说一下相关的基础知识: 线程概念 什么是线程 LWP:light weight process 轻量级的进程,本质仍是进程(在Linux环境下) 进程:独立地址空间,拥有PCB 线 ...
- UNIX环境编程学习笔记(26)——多线程编程(一):创建和终止线程
lienhua342014-11-08 在进程控制三部曲中我们学习了进程的创建.终止以及获取终止状态等的进程控制原语.线程的控制与进程的控制有相似之处,在表 1中我们列出了进程和线程相对应的控制原语. ...
随机推荐
- Android中SDK工具集锦
来源:<Android 4 高级编程> Android提供的SDK中包含有很多用于设计.实现.调试应用程序的工具:比较重要的如下所述: 1. ADB工具 Android应用程序调试桥ADB ...
- 953.Verifying an Alien Dictionary(Map)
In an alien language, surprisingly they also use english lowercase letters, but possibly in a differ ...
- 理解JavaScript【转】
第一题 if (!("a" in window)) { var a = 1; } alert(a); 第二题 var a = 1, b = function a(x ...
- 限制输入字数JS
<tr> <th><b>说明内容:</b><span id="content">(500字以内)</span> ...
- 使用jq 仿 swper 图片左右滚动
<div> <div /</div> <div class="box"> <div class="box-ul" ...
- 2.postman安装及使用
一.postman说明 postman是研发和测试进行接口调试的工具.可以用来很方便的模拟get或者post或者其他方式的请求来调试接口. 二.postman安装 ①作为谷歌浏览器插件安装 参考资料: ...
- 4.23 Linux(3)
2019-4-23 19:03:53 买的服务器第三天感觉超爽!! 发现学习Linux超爽,有种操作的快感!!!!!是Windows比不了的!! 阿里巴巴镜像源 : https://opsx.alib ...
- mysql 水平分表
新建10张表,user_0,user_1,...user_9,方法不可串用,采用hash或取余法,获取要操作的表名,取值用对应存值的方法 1.hash取余法 public function part_ ...
- String类,StringBuffer类转字符数组
String不可变类型和StringBuffer可变类型 String类和StringBuffer类都是字符串表示类,区别在于String对象引用变量是不可变的,而StringBuffer类对象引用变 ...
- java byte 梳理
最近写编解码的代码比较多,抽一点时间梳理下java下byte的解析.在例子代码中主要涉及的知识点就两块: 1.byte代表8个bit,其中最高位是符号位: 2.当我们用String类的getBytes ...