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 ...
随机推荐
- GreenDao 数据库:使用Raw文件夹下的数据库文件以及数据库升级
一.使用Raw文件夹下的数据库文件 在使用GreenDao框架时,数据库和数据表都是根据生成的框架代码来自动创建的,从生成的DaoMaster中的OpenHelper类可以看出: public sta ...
- 继电器是如何成为CPU的(1)
继电器是如何成为CPU的(1) ——<穿越计算机的迷雾>整理和总结 究竟是如何设计的电路,具有计算和控制的智力? 这一点也不高深.本系列文章从初中学的最简单的电路图说起,看看能不能从最初的 ...
- Java基础Map接口+Collections
1.Map中我们主要讲两个接口 HashMap 与 LinkedHashMap (1)其中LinkedHashMap是有序的 怎么存怎么取出来 我们讲一下Map的增删改查功能: /* * Ma ...
- ASP.NET Core的路由[4]:来认识一下实现路由的RouterMiddleware中间件
虽然ASP.NET Core应用的路由是通过RouterMiddleware这个中间件来完成的,但是具体的路由解析功能都落在指定的Router对象上,不过我们依然有必要以代码实现的角度来介绍一下这个中 ...
- H5坦克大战之【玩家控制坦克移动】
自从威少砍下45+11+11的大号三双之后,网上出现了各种各样的神级段子,有一条是这样的: 威少:Hey,哥们,最近过得咋样! 浓眉:对方开启了好友验证,请先添加对方为好友 威少:...... JRS ...
- spring源码分析之context
重点类: 1.ApplicationContext是核心接口,它为一个应用提供了环境配置.当应用在运行时ApplicationContext是只读的,但你可以在该接口的实现中来支持reload功能. ...
- javascript 判断参数类型大全
js 判断类型的在开发中是很常用的,因为js 是弱类型的语言,var 可以接受任何形式的类型,但是在真正的开发中,我们需要根据不同类型做不同的处理,所以这个是必须的精通. 首先需要知道 typeof这 ...
- Servlet监听器笔记总结
监听器Listener的概念 监听器的概念很好理解,顾名思义,就是监视目标动作或状态的变化,目标一旦状态发生变化或者有动作,则立马做出反应. Servlet中的也有实现监听器的机制,就是Listene ...
- WebSocket - ( 一.概述 )
说到 WebSocket,不得不提 HTML5,作为近年来Web技术领域最大的改进与变化,包含CSS3.离线与存储.多媒体.连接性( Connectivity )等一系列领域,而即将介绍的 WebSo ...
- Docker与CI持续集成/CD
背景 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化.容器是完全使用沙箱机制 ...