当执行I/O操作的时候,无论是同步I/O操作还是异步I/O操作,都会调用的Windows的API方法,比如,当读取文件的时候,调用ReadFile函数。该方法会将你的当前线程从用户态转变成内核态,会生成一个I/O请求包,并且初始化这个请求包,这个包中包含一个文件句柄,一个偏移量和一个Byte[]数组。ReadFile会向内核传递,根据这个请求包,windows内核知道需要将这个I/O操作发送给哪个硬件设备。这些I/O操作会进入设备自己的处理队列中,该队列由这个设备的驱动程序维护。
如果此时是同步I/O操作,那么在硬件设备操作I/O的时候,发出I/O请求的线程由于无事可做被windows变成睡眠状态,当硬件设备完成操作后,再唤醒这个线程。这种方式非常直接,但是性能不高,如果请求数很多,那么休眠的线程数也很多,浪费了大量资源。
如果是异步I/O操作,那么情况不同了。.Net中,异步的I/O操作为BeginXXX的形式。该方法在Windows把I/O请求包发送到设备的处理队列后就返回了。同时,在调用异步I/O操作的时候,即调用BeginXXX方法的时候,需要传入一个委托,该委托方法会随着I/O请求包一路传递到设备的驱动程序。在设备处理完I/O请求包后,将该委托再放到CLR线程池队列。在CLR内部有一个IOCP(I/O
completion
port),它提供了在处理多个异步I/O请求的线程模型,可以把这个IOCP看做是一个消息队列,当一个进程创建了一个IOCP,即创建了一个队列。当异步I /
O请求完成时,设备驱动程序就会生成一个I/O完成包,将它按照FIFO方式排队列入该完成端口。之后,会有线程提取完成I/O请求包,并调用之前的委托。IOCP会预分配的线程池,线程数量和CPU数量一致,这样的好处是避免了线程的上下文切换。这种方式比即时创建线程处理I/O请求速度更快。这种机制很好的实现了异步通信,既提高了性能又平衡了资源。
参考资料
《CLR VIA C#》
《Pro .NET Performance》
《Windows核心编程(第5版)中文版》
http://blog.csdn.net/piggyxp/article/details/6922277
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365198(v=vs.85).aspx
同步I/O操作和异步I/O操作,布布扣,bubuko.com