asynchronous I/O——异步I/O

来源:互联网 发布:数据科学家前景好吗 编辑:程序博客网 时间:2024/05/16 16:22
Overlapped I/O,也就是asynchronous I/O——异步I/O。

        目前所有外设的速度(包括硬盘)跟CPU的速度相比仍然是天壤之别,而程序跟外设打交道又是非常正常的事情,因此如何让程序既能进行I/O又不受制于 I/O速度瓶颈的限制是一大课题。而采取异步方式则是一种自然而且有效的方案。也就是说我们调用I/O函数后立即返回继续往下执行,而不必等I/O完成后 再继续,这样就使得I/O操作与我们的程序之间能够并发进行(从用户的观点看却是并行的,看来感性的人类的感觉还是比较容易受欺骗的-_-)。当然,通常 我们都需要知道I/O的执行情况,包括其执行结果。从这个意义上讲,异步去执行的I/O过程跟我们释放出去的一个线程在概念上是比较相似的。
        在win32中,我们可有以下几种方式(或者叫做机制)来实现Overlapped I/O。
1,激发的文件handle
预设操作:
——用FILE_FLAG_OVERLAPPED参数调用CreateFile()函数以便告知被打开的文件以后要进行Overlapped I/O。
——定义一个OVERLAPPED结构并适当填充(hEvent域为空)
执行操作:
——以定义的那个OVERLAPPED结构的地址为参数调用ReadFile()或WriteFile()来进行Overlapped I/O。
等待操作:WaitForSingleObject(), WaitForMultipleObjects(), MsgWaitForMultipleObjects()
等待对象:文件handle
取得结果:GetOverlappedResult()
缺陷:
不 能方便地从文件操作级获知结果。用GetOverlappedResult()得到的只是最近一个该文件上的操作的结果,要想获得在该文件上的每个操作的 结果必须在每个操作后用GetOverlappedResult()来获取结果。这样做效率比较低,也增加了程序的复杂性,降低了程序的灵活性。
2、激发的Event对象
预设操作:
——用FILE_FLAG_OVERLAPPED参数调用CreateFile()函数以便告知被打开的文件以后要进行Overlapped I/O。
——定义一个OVERLAPPED结构并适当填充(hEvent域为一个手动激发的Envet对象)
执行操作:
——以定义的那个OVERLAPPED结构的地址为参数调用ReadFile()或WriteFile()来进行Overlapped I/O。
等待操作:WaitForMultipleObjects(), MsgWaitForMultipleObjects()
等待对象:所关心的操作对应的Event对象
取得结果:Wait函数的返回结果
缺陷:
——等待多个对象的Wait函数对所等待的对象数目有限制MAXIMUM_WAIT_OBJECTS(比如64个)。
——必须不断地根据Wait函数的返回结果来判断是哪个Event对象被激发,从而作出相应的反应。
3、异步过程调用(Asynchronous Precudure Call,APC)
预设操作:
——用FILE_FLAG_OVERLAPPED参数调用CreateFile()函数以便告知被打开的文件以后要进行Overlapped I/O。
——定义一个OVERLAPPED结构并适当填充(hEvent域不是必要的,此时可以用来存放一个用户自定义结构的指针)
——定义一个回调函数
执行操作:
——以定义的那个OVERLAPPED结构的地址以及回调函数地址为参数调用ReadFileEx()或WriteFileEx()来进行Overlapped I/O。
等待操作:不必等待
等待对象:不必等待
取得结果:通过一个OVERLAPPED指针传给回调函数
缺陷:
——有好几个I/O API并不支持APC,比如listen(), WaitCommEvent()
——只有发出Overlapped I/O的那个线程才能提供对应的回调函数,这样不利于构建可扩展系统
4、I/O Completion Ports
说明:
I/O Completion Ports提供了这样一种机制:将一堆线程和一堆文件handle关联起来,使得这堆handle中的任何一个被激发时都会导致那堆线程中的一个被激活 (如果存在的话)并为之服务,完成服务后的线程不会被结束,而是继续回到那堆线程中,继续等待被激活。其实这就是线程池的概念。
另外,这堆线程只能用作这样一个单一用途,除此之外不能去做其他任何事情。
预设操作:
——用FILE_FLAG_OVERLAPPED参数调用CreateFile()函数以便告知被打开的文件以后要进行Overlapped I/O。
——产生一个I/O Completion Port对象:CreateIoCompletionPort()
——将该对象和文件handle关联起来:CreateIoCompletionPort()
——产生一堆线程:CreateThread()
——让每一个线程都在该I/O Completion Port对象上等待:GetQueuedCompletionStatus()
执行操作:
—— 对那些文件handle进行一些Overlapped I/O。ConnectNamePipe(), DeviceIoControl(), LockFileEx(), ReadFile(), TransactNamePipe(), WaitCommEvent(), WriteFile()
等待操作:GetQueuedCompletionStatus()
等待对象:I/O Completion Port packet
取得结果:通过GetQueuedCompletionStatus()的参数传递给服务线程
缺陷:
【附】
——所谓可扩展(scalable)系统,是指能够藉着增加RAM或磁盘容量或CPU个数而提升系统性能的系统。
——系统可能会让Overlapped I/O立即执行的情况:
————请求的数据量比较小
————系统可以立即满足请求(比如请求的数据已经在缓存)
——系统肯定会让Overlapped I/O立即执行的情况:
————进行一个写入操作而造成文件的扩展
————读写一个压缩文件
——不让系统激发I/O Completion Ports的方法:
在对已经跟某I/O Completion Port关联的文件进行操作时,产生一个Event对象用以填充其OVERLAPPED参数的hEvent域,该Event对象是手动重置的,并且其handle的最低位为1。

原创粉丝点击