I/O完成端口

原文:https://msdn.microsoft.com/en-us/library/aa365198(v=vs.85).aspx

第一次翻译MSDN文档,虽然很多语句还是读不懂,但是坚持翻译完一篇文章之后真的感觉收获颇丰。有些概念用英文的思维很容易理解,但是这些概念要翻译成汉语却总感觉找不合适的描述方法。由于属于初学者,水平有些,译文中难免会有错误和纰漏,如在阅读中发现,请见谅和指出,感激不尽。

I/O完成端口
I/O完成端口为解决多处理器系统(multiprocessor system)中的多重异步I/O请求(multiple asynchronous I/O requests)问题提供了一个高效的线程模型。当一个进程(process )创建了一个I/O完成端口时,操作系统会创建一个队列来处理与之相关的请求。需要处理大量异步请求的进程,如果使用与事先创建好的线程池(pre-allocated thread pool)相关联的I/O完成端口来处理这些请求,将会比传统方法(当接到一个新的I/O请求后为其创建一个线程)更快更高效。


I/O完成端口是如何工作的
CreateIoCompletionPort这个函数被来创建完成端口,并将文件句柄(file handles)与该端口关联。当一个与完成端口相关联的句柄完成了对异步IO请求的处理后,一个IO完成包(an I/O completion packet)会加入IO完成端口队列的队尾。该方法有很多用途,其中一个主要用途是——to combine the synchronization point for multiple file handles into a single object(不会翻)。需要注意的是,完成包虽然是以先入先出的顺序被添加到队列队尾,但完成包移除时的顺序可能与此不同。
/*
注意:
这里提到的“文件句柄”,指的是a system abstraction representing an overlapped I/O endpoint(不会翻),而不仅指硬盘上的文件。例如,它可以是一个network endpoint(不会翻),TCP套接字(TCP socket),命名管道(named pipe),或者一个邮槽(mail slot)。下面这些函数可以用来启动一个用完成端口完成的I/O操作(to start I/O operations that complete by using I/O completion ports)。要用完成端口机制,你必须给这个函数一个OVERLAPPED实例和一个已经与一个完成端口关联的文件句柄(通过CreateIoCompletionPort关联)。相关函数名如下:
ConnectNamedPipe,DeviceIoControl,LockFileEx,ReadDirectoryChangesW,ReadFile,TransactNamedPipe,WaitCommEvent,WriteFile,WSASendMsg,WSASendTo,WSASend,WSARecvFRom,WSARecvMsg,WSARecv
*/


当一个文件句柄与完成端口关联后,传入的status block(不会翻)在完成包从完成端口中移除之前是不会被更新的。但是有一种特殊情况除外—— the original operation returns synchronously with an error(不会翻)。一个线程(不论是主线程还是主线程的子线程)调用GetQueuedCompletionStatus后会挂起,一直挂到有一个完成包进入完成端口队列,而不是挂到异步请求处理完成的时候。阻塞在完成端口上的线程按先入后出的顺序被释放,但是完成包会按照先入先出的顺序分配给这些阻塞线程。也就是说,系统向线程分配完成包时,会把等待时间最长的包分配给等待时间最短的线程。
一个线程调用GetQueuedCompletionStatus与一个完成端口关联后,这种关联只有在如下情况会解除:1.线程终止 2.线程调用GetQueuedCompletionStatus与另一个完成端口关联 3.完成端口关闭(这段话的意思是:虽然一个完成端口可以关联多个线程,但是一个线程只能与一个完成端口关联,换言之,线程与完成端口是“多对一”的关系)


一个完成包加入到完成端口队列后,系统首先会检测与该完成端口关联的线程有多少正在运行。如果正在运行的线程数少于concurrency value(下文对其有介绍),系统会将完成包交给一个正在等待的线程去处理,否则不会。当一个线程处理完完成包之后,它通常会再次调用GetQueuedCompletionStatus,此时它会紧接着去处理下一个完成包,如果队列中没有完成包,它将会挂起。


一个线程可以调用PostQueuedCompletionStatus来将一个完成包送入完成端口队列。一个线程可以用这用方法在进程内与其它线程通信,而且也可以接到系统发出的完成包。PostQueuedCompletionStatus允许不是正在执行I/O完成包处理的应用(我的理解是这个“应用”指的是没有与相应完成端口绑定的线程,否则没必要再啰嗦这么一段吧。以后会测试一下。)向完成端口发送有特殊目的的完成包。这中机制的一个应用是——可以向工作线程通知外部事件。
I/O完成端口的句柄和与之相关联的文件句柄 are known as references to the I/O completion port(不会翻)。完成端口会在不存在对它的引用时被释放。因此,要释放一个完成端口和与它相关的系统资源时,需要先合理的关闭掉所有与之相关的句柄。在上述条件具备时,可以调用CloseHandle来关闭I/O完成端口。(我的理解是,如果在关闭所有与I/O完成端口相的文件句柄之前调用了CloseHandle,是不能将完成端口及其相关系统资源释放掉的,这样就造成了内存泄露)。
/*
注意:一个完成端口与创建它的进程相关联,并且不能被其它进程共享。但是一个句柄在一个进程内的线程间是可以共享的。
*/
线程和并发
完成端口最值得注意的一个特性就是它的并行值(concurrency value一个处理器中的最大并行线程数)。一个完成端口的concurrency value在CreateIoCompletionPort时通过NumberOfConcurrentThreads 这个参数来设置。这个值限定了与完成端口相关的运行线程的数目。当与完成端口相关的运行线程数目超过该值时,系统会阻塞其它等待线程,直到运行线程数小于这个值。(意思就是最多只有NumberOfConcurrentThreads 个运行线程。)


最高效的情况是队列中有完成包在等待处理,但是却没有等待线程可以。试想一下,如果NumberOfConcurrentThreads 设为1时会发生什么情况?在该值设为1时,只有最后一个调用GetQueuedCompletionStatus的线程可以运行,因为线程分配原则是“后进先出”。
/*
注意:
在之前的例子中,处于等待状态的线程是没有用的(useless),并且永远不会启动,但是,这种情况是基于一个假设——正在运行的那条线程不会被置为等待状态(其实这条运行的线程可以由三种方法被置为等待状态:1.其它机制 2.终止线程 3.关闭与该线程相关的完成端口 此处翻译很可能有误。but that assumes that the running thread never gets put in a wait state by some other mechanism, terminates, or otherwise closes its associated I/O completion port.)在设计一个程序时,需要考虑这些情况。
最好的全局最大值(overall maximum value)应该与计算机上的CPU数相同。如果你的单个事务处理时间很长,你可以增大你的并行值(concurrency value)以让更多的线程跑起来。这样做有好处也有坏处,好处是可以有更多完成包被同时处理,坏处是每个完成包的处理时间会变长(因为线程多了上下文切换用的时间就会变长)。你可以通过使用分析工具( profiling tools)来试验出一个最高效的并行值(concurrency value)。
*/


当一个正在运行了线程由于某些原因进入等待状态是(例如调用了SuspendThread函数),系统允许一个处于等待队列的线程去处理下一个完成包,这时,可能会出现短时间的运行线程数大于最大并行值的情况。但是,之后系统便不会再让更多的等待线程被激活,直到运行线程数小于最大并行值。这就是建议你在线程池中建立的线程数需要大于你设置的最大并行值的原因。线程池管理不属于本话题讨论的范围,但是有一个关于线程池中最佳线程数的经验值——系统上处理器数量的2倍(a good rule of thumb is to have a minimum of twice as many threads in the thread pool as there are processors on the system)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值