IOCP是什么?

1. IOCP 浅析与实例
众所周知,为了绝对同步,所以很多模式都采用的是同步模式,而不是异步,这样就会产生很大情况下在等待,CPU在切换时间片,从而导致效率比较低。
自从MS在winsocket2中引入了IOCP这个模型之后,他才开始被大家所认知。


IOCP (I/O Completion Port),中文译作IO完成端口,他是一个异步I/O操作的API,他可以高效的将I/O事件通知给我们的应用程序,那游戏项目来说,就是客户端或者服务器。

他与Socket基础API  select()或其他异步方法不同的是,他需要讲一个Socket和一个完成端口绑定在一起,然后就可以进行网路通信了。


2.  什么是同步/异步?

所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。
按照这个定义,其实绝大多数函数都是同步调用(例如sin, isdigit等)。

异步的概念和同步相对。当一个异步过程调用发出后,调用者不能立刻得到结果。
实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。

逻辑上通俗来讲是完成一件事再去做另外一件事情就是同步,而一起做两件或者两件以上的事情就是异步了。
类似于Win32API中的SendMessage()和PostMessage(),你可以将他理解成单线程和多线程的区别。

3.  什么是阻塞/非阻塞?

阻塞调用是指调用结果返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回。
可能阻塞和同步有点类似,但是同步调用的时候线程还是激活的,而阻塞时线程会被挂起。


非阻塞调用和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。


对象的阻塞模式和阻塞函数调用


对象是否处于阻塞模式和函数是不是阻塞调用有很强的相关性,但是并不是一一对应的。阻塞对象上可以有非阻塞的调用方 式,我们可以通过一定的API去轮询状态,在适当的时候调用阻塞函数,就可以避免阻塞。而对于非阻塞对象,调用特殊的函数也可以进入阻塞调用。函数 select就是这样的一个例子。

4.对IOCP的评价如何?

I/O完成端口可能是Win32提供的最复杂的内核对象。 Jeffrey Richter

这是实现高容量网络服务器的最佳方法。Microsoft Corporation

完成端口模型提供了最好的伸缩性。这个模型非常适用来处理数百乃至上千个套接字。Anthony Jones & Jim Ohlund


I/O completion ports特别显得重要,因为它们是唯一适用于高负载服务器[必须同时维护许多连接线路]的一个技术。
Completion ports利用一些线程,帮助平衡由I/O请求所引起的负载。这样的架构特别适合用在SMP系统中产生的”scalable”服务器。 Jim Beveridge & Robert Wiener


5.  IOCP中的完成是指什么意思?

网络通信说白了就是将一堆数据发过来发过去,到底还是数据的操作。
不过大家都知道I/O操作是非常慢的,包括打印机、调制解调器、硬盘等,至少相对于CPU来说是非常慢的。
坐等I/O是很浪费时间的事情,可能你只需要读取100KB的数据,假设读了0.1秒,假设CPU是3.0G Hz,那么CPU已经运行了0.3G次了,
所以CPU这个时候就不满意了,哥这么NB,为什么要等你?


所以我们用另外一个线程来处理I/O操作,使用重叠IO(Overlapped I/O)技术,应用程序可以要求OS为其传输数据,
在完成的时候通知应用程序,然后在进行相应操作,这也就是为什么叫完成的原因。这可以使得应用程序在I/O传输期间可以做其他事情,
这也可以最大限度的利用线程,而让最NB的CPU不至于痴痴等待。


6.    IOCP出现的意义?

写过网络程序的朋友应该很清楚网络程序的原型代码,startup一个WSADATA,
然后建立一个监听socket对象,绑定一个服务器地址,
然后开始监听,无限循环的accept来自客户端的消息,
建立一个线程来处理消息,accept之后线程就被挂起了,知道收到来自客户端的消息。


这样的模型中服务器对每个客户端都会创建一个线程,优点在于等待请求的线程只做很少的事情,大部分时间该线程都在休息,因为recv函数是阻塞的。

所以这样的效率并不是很高,NT小组意识到这样CPU的大部分时间都耗费在线程的上下文切换上,线程并没有抢到cpu时间来处理自己的工作。


NT小组想到了一个解决办法,实现开好N个线程,将用户的消息都投递到一个消息队列中去,然后事先开好的N个线程逐一从消息队列中取出消息并加以处理,
就可以避免为每一个客户端的请求单独开线程,
既减少了线程的资源,也提高了线程的利用率。
所以I/O完成端口的内核对象在NT3.5中首次被引入,MS还是比较伟大的。


这里你也看到了,IOCP其实称作是一种消息处理的机制差不多,而叫完成端口估计也是有历史原因,亦或者是因为他提供了用户与操作系统的一种接口吧。


IOCP百度百科 http://baike.baidu.com/link?url=TlWvNIC9WkRDrxqTD_lh--21gi3JLM5HjmIeB_ozmJgpPoXx-ZXAA6V0MuzGbUrMwk-bCuoRn6UXSNtA6_3HTK
IOCP完成端口的一个简单封装类  http://blog.csdn.net/sky04/article/details/5667190
完成端口IOCP详解  http://blog.csdn.net/beyond_cn/article/details/9336043
IOCP 原理  http://blog.chinaunix.net/uid-11640640-id-2139870.html
完成端口I/O模型是一种高效的异步 I/O 模型,其工作原理如下: 1. 程序先创建一个完成端口对象,然后将需要进行异步 I/O 操作的文件句柄或套接字与完成端口对象关联起来。 2. 当异步 I/O 操作完成时,操作系统会将完成信息放入完成端口对象的队列中。 3. 程序可以通过调用 GetQueuedCompletionStatus 函数来获取完成信息。该函数会阻塞等待直到有完成信息到达,或者设置超时时间。 4. 获取到完成信息后,程序可以处理完成的操作,并重新发起新的异步 I/O 操作。 完成端口模型的异步完成通知机制是由操作系统内核实现的。当异步 I/O 操作完成时,操作系统会将完成信息放入完成端口对象的队列中,并唤醒等待在 GetQueuedCompletionStatus 函数上的线程。程序可以通过调用 GetQueuedCompletionStatus 函数获取完成信息。 IOCP 内核对象维护以下 5 个队列: 1. 空闲线程队列:存放空闲的线程对象。 2. 活动线程队列:存放正在执行异步 I/O 操作的线程对象。 3. 完成队列:存放完成的 I/O 操作的信息。 4. 关闭队列:存放需要关闭的文件句柄或套接字。 5. 绑定队列:存放需要进行绑定操作的文件句柄或套接字。 完成队列中存放完成的 I/O 操作的信息,包括完成的操作类型、操作结果、完成的数据大小等信息。 IOCP 通过维护线程池来提高异步 I/O 操作的效率。程序可以通过调用 CreateThread 或者 ThreadPoolCreate 函数来创建线程池。线程数量上限应该根据系统硬件性能和程序的实际需要来设置,一般情况下,线程数量应该小于 CPU 核心数的两倍。 使用该 I/O 模型设计程序的步骤如下: 1. 创建完成端口对象。 2. 创建线程池,将空闲线程对象加入空闲线程队列。 3. 将需要进行异步 I/O 操作的文件句柄或套接字与完成端口对象关联起来。 4. 发起异步 I/O 操作。 5. 等待完成信息到达,获取完成信息。 6. 处理完成信息,重新发起新的异步 I/O 操作。 7. 当需要关闭文件句柄或套接字时,将其放入关闭队列。 8. 当需要绑定文件句柄或套接字时,将其放入绑定队列。 9. 程序结束时,释放资源。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值