Node.js中的IOCP

来源:互联网 发布:visio2007 网络拓扑图 编辑:程序博客网 时间:2024/05/21 09:10

想必有些人看过朴灵的《深入浅出Node.js(五):初探Node.js的异步I/O实现》http://www.infoq.com/cn/articles/nodejs-asynchronous-io,此篇写的还是很精彩的,特别是对于原理的分析,说明作者在此浸淫已久,不过个人认为其中对于IOCP的理解不是很精准,或者说会引起读者歧义,且看以下原文中描述:

那么在Windows平台下的状况如何呢?而实际上,Windows有一种独有的内核异步IO方案:IOCP。IOCP的思路是真正的异步I/O方案,调 用异步方法,然后等待I/O完成通知。IOCP内部依旧是通过线程实现,不同在于这些线程由系统内核接手管理。IOCP的异步模型与Node.js的异步 调用模型已经十分近似。
实际上,本篇中的流程介绍和图都是比较精准的,只是对于IOCP的理解上有些偏差,这里确实是用到了IOCP,但是并未体现IOCP的异步功能,下面我着重讲下一下IOCP的异步机制,大家可以对比看看就明白了。

先介绍三个重要的IOCP函数以及他们的底层函数,-》代表调用,Nt*、Io*、Ob*等函数是内核函数

1、CreateIoCompletionPort-》NtCreateIoCompletion-》ObCreateObject

伪代码:
if (IOCP不存在)

    NtCreateIoCompletion // 创建一个

}

else

    NtSetInformationFile  // 将已经存在的IOCP对象与指定的文件对象绑定

这是函数有两个功能,一是创建IOCP对象,二是把IOCP对象跟一个文件对象(理论上只要是文件对象就行,windows上很多东西都是文件对象,socket,串口,磁盘等等,并不一定是狭隘的文件)绑定;一般使用的时候要调用两次分别完成以上两个功能,初学者还是很困惑的。

2、GetQueuedCompletionStatus-》NtRemoveIoCompletion-》KeRemoveQueue


这个看文件名大家都应该能明白意思了,就是从内核中一个队列中取东西。

3、PostQueuedCompletionStatus-》IoSetIoCompletion-》KeInsertQueue

也很简单,向内核中一个队列放东西

看到这里,大家会看到原来IOCP就是一个生产者、消费者模型啊,没错,虽然细节远远比这个复杂,但是大致上可以这么理解。

以上三个函数是IOCP最常用的三个函数,但是第三个并不是必须的,在真正异步IO的时候是不需要第三个函数的,是的,没有这个生产者也可以,请接着看:

在内核中,一个文件对象的操作真正完成后,会调用IoCompleteRequest函数。

IoCompleteRequest-》IofCompleteRequest-》IopfCompleteRequest—发起内核APC—》IopCompleteRequest

发起内核APC是为了使IopCompleteRequest工作在调用者的线程空间中,因为这个里面涉及到一些内核数据到用户态数据的复制,所以必须使用跟调用时候相同的线程环境

重点看IopCompleteRequest,以下是代码节选:

 if (port && irp->Overlay.AsynchronousParameters.UserApcContext) // 如果port不为空,则。。。(后面条件先忽略,调用CreateIoCompletionPort跟IOCP对象关联过以后,文件对象中的port就不为空了,好像明白点了吧?)

{

 

            //

            // If there is a completion context associated w/this I/O operation,

            // send the message to the port. Tag completion packet as an Irp.

            //

 

            irp->Tail.CompletionKey = key;

            irp->Tail.Overlay.PacketType = IopCompletionPacketIrp;

 

            KeInsertQueue( (PKQUEUE) port,                                                // 原来生产者在这里

                           &irp->Tail.Overlay.ListEntry );

 }

从操作系统层面上看,这才是真正地异步(前摄式)模型!!!

所以,Node.js在windows下对文件的操作虽然使用了IOCP,但也不是真正的操作系统层面上的异步模型,大家可以回顾一下朴灵的原著。

看到这里没晕的,应该明白我想讲什么了吧,简单一句话概括吧 ,凡是用户态自己调用PostQueuedCompletionStatus函数的都不是真正的去使用IOCP内核异步特性的!是另有用途的,只是把IOCP看成一个普通的通知队列而已!

原创粉丝点击