IOCP Internals
Buffer Type
Buffer I/O
针对Buffer I/O的请求,系统会为其分配一个非换页内存作为缓存区,其大小等同于I/O请求的缓存区大小。对于写操作,I/O管理器在创建IRP时,将请求者的缓存区数据拷贝到申请得到的非换页缓存区中。对于读操作,I/O管理器将会在I/O完成时,将数据从非换页内存缓存区中拷贝到请求者的缓存区中。在I/O完成后,会释放掉该次申请到的非换页缓存区。
Direct I/O
I/O管理器在处理Direct I/O类型的请求时,会将请求者的缓存区锁定在内存中,使其变成不可换页的内存。当该I/O处理完成时,I/O管理器会解除请求者缓存区的锁定。I/O管理器用MDL机制锁定请求的缓存区,在需要操作缓存区的时候,可以使用相应的API映射请求者的缓存区到系统的地址空间。
Neither I/O
对于此种I/O请求,I/O管理器不会执行任何缓存区管理,对应的缓存管理交给相应的设备驱动程序自己处理。但是不管设备驱动程序如何处理,都不会超过上面两种方式的处理。
I/O Type
Synchronous I/O
应用程序发出的大部分I/O操作是同步的。在设备处理I/O请求时,应用程序需要一直等待,直到I/O完成时,设备返回结果,最终程序才可以继续执行。并且可以立即访问这些被传输的数据。
Asynchronous I/O
异步I/O是程序先发出一个I/O请求,交由设备处理,程序可以继续执行。该程序可以在处理其他事务后检查I/O是否完成,或者当I/O完成时,I/O管理器主动告诉程序I/O已完成。 为了在WINDOWS使用异步I/O,打开文件或建立SOCKET时,需要指定FILE_FLAG_OVERLAPPED标志。
在发起一个异步I/O请求后,必须十分小心:在I/O未完成时,不能访问该I/O操作中任何数据,要确保缓存区有效。发起异步I/O后,为了拿到最终有效的数据,需要做同步操作,WINDOWS下支持OVERLAPPED,也就是基于EVENT内核对象同步,APC(异步过程调用)还有IOCP(I/O Completion Port)。
I/O Completion Process
当一个设备处理完I/O请求时,会调用内核API IoCompleteRequest,通知I/O管理器自己完成了该I/O请求。为了安全操作用户的缓存区,I/O管理器会根据I/O请求类型会执行相应的动作:如果是同步I/O请求,那么可以直接操作请求的缓存区;如果是异步I/O请求,I/O管理器会延迟该I/O完成动作直到请求者对应的地址空间为止。完成该动作的方式是向该请求的线程投递一个APC。在切换到该请求的I/O请求所在的线程时,该APC会得到执行。会把已完成的I/O请求中得到的数据拷贝到对应的缓存区中。这个时候,对于异步I/O请求,像ReadFileEx/WriteFileEx可以投递一个APC例程,I/O管理器在执行I/O完成最后一步后,检测到有APC,就把该APC例程投递到请求线程内,当线程处于警告状态时(SleepEx, WaitForSingleObjectEx)会得到执行。如果该异步I/O请求对应的文件对象或者SOCKET绑定了IOCP,则会在处理完成时,把对应的OVERLAPPED结构投递到IOCP队列中。 这也就是当处理WSARecv时(假设该请求的SOCKET已经绑定了IOCP),如果这个时候系统中已经缓存了数据,这个时候不需要判断是否接收到数据,而只需要判断LastError是否是ERROR_IO_PENDING的原因。
IOCP
在实现服务端程序时,常用的一个简单处理网络请求的方式是针对连接分配一个线程单独处理。太少或太多都会带来性能问题。线程太少,对于客户端的请求无法及时处理;太多,会导致线程频繁轮换。理想的情形是,在服务器的每个处理器上都有一个线程在积极的处理一个用户的请求,如果有其他的请求在等待的话,会立刻有线程来处理这些请求。为了达到这一最优过程得以最终正确的进行,需要有一个办法,能够在处理客户请求的线程在I/O阻塞时,能激活另一个线程处理其他请求。
WINDOWS中引入了IOCP机制来实现这一最优过程。IOCP的内部是依靠一个叫队列的内核对象完成这一过程。当创建一个文件句柄或者SOCKET时,可以把句柄与IOCP句柄绑定在一块,任何以此句柄发起的异步I/O请求操作在完成时都会生成一个CompletionPackage,并把该CompletionPackage排队到该完成端口上,也就是排队到内部的队列内核对象上。应用程序可以通过API GetQueuedCompletionStatus获取已完成的CompletionPackage,处理已完成的I/O数据。
WINDOWS API中的WaitForMultipleObjects函数提供了类似的功能,但是,完成端口的好处是,在系统协助下并发是可控的。处理方式是应用程序主动处理客户端请求的线程的数量。前面提到,理想情况是每个处理器都由一个线程在处理客户端请求。在创建IOCP时,会制定一个值,这个值为关注IOCP的线程数。因为IOCP的内部机制依赖于队列内核对象,在WINDOWS中,内核对象都是可等待的,也就是用类似WaitForSingleObject类似的机制。而IOCP在创建时制定的值会传给内部的队列内核对象作为一个并发值。如果与IOCP关联的活动线程的数量超过了这个并发值,那么正在该IOCP上等待的线程将不允许运行。当有异步I/O完成时,会投递CompletionPackage到绑定的IOCP中的队列对象中,如果此时有线程正在等待,则会直接把这个CompletionPackage交给这个正在等待的线程处理。这样的过程中,没有线程环境切换,更好的把CPU的能力利用起来。
关于IOCP的并发值,Microsoft的指导原则是,将并发值设置成大约等于该系统中处理器的数目。
参考文档:
- 《深入解析Windows操作系统第四版》
- Windows Research Kernel
IOCP Internals的更多相关文章
- iocp 小例子
2016-08-3116:44:09 server 端 /******************************************************************* aut ...
- 简单说一个IOCP不好的地方
感谢rulary的指正!博文中我对IOCP的理解是有误的,正确的方式请见评论区rulary的回复! 由于项目实际设计的需要,最终IO事件处理没有采用IOCP,而是采用了NT6.0引入的WSAPoll, ...
- IOCP和WSA异步协同客户端版
有些小伙伴看了之前发的WIN平台下IOCP和WSA异步协同处理SOCKET后有些疑惑,所以就画了个简易流程图+架构图发上来给小伙伴参考 简单说,WSA异步控制CONNECT,IOCP控制WSASend ...
- windows WSABUF 结构在IOCP 中应用时两个成员变量的意义
WSABUF 结构的原型如下: typedef struct __WSABUF { u_long len; char FAR *buf; } WSABUF, *LPWSABUF; 该结构在IOCP 中 ...
- IOCP入门
完成端口(Completion Port)详解 此文讲解最好,也很全面一下其他文章看看就行,也可不看. 单句柄数据,单IO数据 此文讲述比较清晰,可以辅助理解上文. IOCP编程之基本原理:http: ...
- 解剖SQLSERVER 完结篇 关于Internals Viewer源代码
解剖SQLSERVER 完结篇 关于Internals Viewer源代码 大家可能都用过Internals Viewer这个软件 <查看SQLSERVER内部数据页面的小插件Internals ...
- Key Components and Internals of Spring Boot Framework--转
原文地址:http://www.journaldev.com/7989/key-components-and-internals-of-spring-boot-framework In my prev ...
- iocp还是select
上一个项目libevent应该是select,现在libuv是iocp,都知道Windows下iocp比select效率高,boost asio 也是iocp,但具体使用select和iocp发现没有 ...
- 再谈select, iocp, epoll,kqueue及各种I/O复用机制
原文:http://blog.csdn.net/shallwake/article/details/5265287 首先,介绍几种常见的I/O模型及其区别,如下: blocking I/O nonbl ...
随机推荐
- TODO:小程序开发过程之体验者
TODO:小程序开发过程之体验者 1. 小程序开发过程,先下载开发者并安装开发者工具,现在腾讯开放测试了,普通用户也可以登录开发者工具,如图普通用户登录为调试类型,但是只能建立无AppID的项目 如果 ...
- JavaScript动画-拖拽改变元素大小
▓▓▓▓▓▓ 大致介绍 拖拽改变元素大小是在模拟拖拽上增加了一些功能 效果:拖拽改变元素大小 ▓▓▓▓▓▓ 拖拽改变元素大小原理 首先这个方块得知道我们想要改变这个它的大小,所以我给它设定一个范围,当 ...
- C++的内存泄漏检测
C++大量的手动分配.回收内存是存在风险的,也许一个函数中一小块内存泄漏被重复放大之后,最后掏空内存. 这里介绍一种在debug模式下测试内存泄漏的方法. 首先在文件的开头以确定的顺序写下这段代码: ...
- Javascript学习笔记
Javascript 2016年12月19日整理 JS基础 Chapter1 JS是一门运行在浏览器客户端的脚本编程语言,前台语言 组成部分 1. ECMAscript JS标准 2. DOM 通过J ...
- Cesium简介以及离线部署运行
Cesium简介 cesium是国外一个基于JavaScript编写的使用WebGL的地图引擎,一款开源3DGIS的js库.cesium支持3D,2D,2.5D形式的地图展示,可以自行绘制图形,高亮区 ...
- Zookeeper常用命令
http://www.cnblogs.com/chengxin1982/p/3997706.html
- Java泛型的历史
为什么Java泛型会有当前的缺陷? 之前的章节里已经说明了Java泛型擦除会导致的问题,C++和C#的泛型都是在运行时存在的,难道Java天然不支持“真正的泛型”吗? 事实上,在Java1.5在200 ...
- NoSql1 在Linux(CentOS)上安装memcached及使用
前言: 今天是初五,生活基本要从过年的节奏中回归到正常的生活了,所以想想也该想想与工作有关的事情了.我之前在工作中会经常使用memcached和redis,但是自己一直没有时间系统的好好看 ...
- 使用 GCC 和 GNU Binutils 编写能在 x86 实模式运行的 16 位代码
不可否认,这次的标题有点长.之所以把标题写得这么详细,主要是为了搜索引擎能够准确地把确实需要了解 GCC 生成 16 位实模式代码方法的朋友带到我的博客.先说一下背景,编写能在 x86 实模式下运行的 ...
- 使用Nginx+Lua代理Hadoop HA
一.Hadoop HA的Web页面访问 Hadoop开启HA后,会同时存在两个Master组件提供服务,其中正在使用的组件称为Active,另一个作为备份称为Standby,例如HDFS的NameNo ...