asynchronous i/o

转载: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。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
自从计算机的诞生以来,I/O(输入/输出)操作一直是计算机系统中重要的组成部分。最早期的计算机系统使用基于阻塞I/O的模型,这意味着当一个I/O操作发生时,整个系统都会被阻塞,直到操作完成。这种模型在处理大量并发请求时效率较低。 随着计算机系统的发展,为了提高I/O操作的效率,出现了一种新的模型称为非阻塞I/O(non-blocking I/O)。非阻塞I/O允许应用程序在等待I/O操作完成时继续执行其他任务,而不会被阻塞。然而,非阻塞I/O模型需要应用程序轮询(polling)I/O状态,这对于处理大量并发请求仍然不够高效。 在这种背景下,操作系统提供了一种新的I/O模型称为异步I/O(asynchronous I/O),也被称为事件驱动I/O。异步I/O允许应用程序发起一个I/O操作,然后继续执行其他任务,当I/O操作完成时,操作系统会通知应用程序。这种模型可以更好地处理大量并发请求,提高系统的吞吐量和响应性能。 Java语言也随着时间的推移逐渐发展了相应的I/O模型。最早期的Java版本使用BIO(Blocking I/O)模型,然后在Java 1.4中引入了NIO(New I/O)模型,提供了非阻塞I/O的支持。NIO通过引入缓冲区(Buffer)和通道(Channel)的概念,使得应用程序可以使用单个线程处理多个I/O操作,提高了并发处理能力。 随后,Java 7引入了NIO.2,也称为AIO(Asynchronous I/O),提供了异步I/O的支持。AIO通过引入异步操作和回调机制,允许应用程序在I/O操作完成时得到通知,而不需要轮询。这种模型进一步提高了Java应用程序的并发性和响应性能。 综上所述,从最早的BIO模型到NIO和AIO,Java的I/O模型逐渐演进,提供了更高效、更灵活的处理方式,使得Java应用程序能够更好地应对并发请求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值