翻译 异步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中我们列出了进程和线程相对应的控制原语. ...
随机推荐
- CF715B. Complete The Graph
CF715B. Complete The Graph 题意: 给一张 n 个点,m 条边的无向图,要求设定一些边的边权 使得所有边权都是正整数,最终 S 到 T 的最短路为 L 1 ≤ n ≤ 100 ...
- nginx.conf 中php-ftp配置
location ~ .php$ { root /home/www; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_par ...
- C++第四课:类的使用(二)[个人见解]
前面说到C++类的名字自定义要有含义,成员函数名也同样如此. 一个好的程序员除了让自己能看懂代码外,那是能力,也能让别人看懂,那是本事. 我们来看第一个特性:继承! 什么是继承? 小编不说概念性的定义 ...
- Windows 2003 防火墙开启后无法访问FTP解决办法
最近遇到一个比较郁闷的问题,服务器开启防火墙后电脑就无法访问服务器的防火墙,但是防火墙又不能关,在例外中添加端口21也不管用. 后来在网上终于找到了一个解决方案,可以在不关掉防火墙的情况下访问服务器的 ...
- 小白学习随笔the first week
The First Week 一.计算机基础 1.软件(应用程序) 2.解释器/编译器 - 解释型语言:将代码每一行传递给计算机一行,常用编程语言python,PHP,Ruby. - 编译型语言:将代 ...
- 打包java程序生成exe
打包java程序生成exe 目标 我们知道c++的控制台程序编译运行以后就会生成一个exe可执行文件,在电脑上可以直接双击运行,但是java是跨平台的语言,编译运行以后的字节码文件.class是和平台 ...
- Android Gradle Task
Tasks runnable from root project ------------------------------------------------------------ Androi ...
- Hadoop集群搭建-full完全分布式(三)
环境:Hadoop-2.8.5 .centos7.jdk1.8 一.步骤 1).4台centos虚拟机 2). 将hadoop配置修改为完全分布式 3). 启动完全分布式集群 4). 在完全分布式集群 ...
- Tensorboard可视化
# -*- coding: utf-8 -*-"""Created on Sun Nov 5 09:29:36 2017 @author: Admin"&quo ...
- return和throw某些特性相似
拷贝构造函数的调用拷贝构造函数会在以下三中情况下被调用(1)当类的一个对象去初始化该类的另一个对象时 int main(){ Point a(1,2); Point b(a);//用对象a初始化对象b ...