Windows的同步I/O和异步I/O

时间:2020-12-01 06:22:28

同步I/O操作

执行步骤

1.        程序通过FileStream对象来打开磁盘文件,然后调用Read方法(内部调用Win32 ReadFile函数),从文件中读取数据。这时,线程从托管代码转变为本机/用户模式代码。

2.        Win32 ReadFile函数生成一个I/O请求包(IRP),并传递给Windows内核。

3.        Windows内核将IRP传送给I/O硬件设备驱动程序的IRP队列。

4.        硬件设备执行I/O操作。在此期间,发出I/O请求的线程将变成睡眠状态。这样可以避免浪费CPU时间,但依然会浪费内存空间。因为线程的用户模式栈、内核模式栈、线程环境块和其他数据结构仍在内存中,而且无人访问。

5.        在硬件设备完成I/O操作后,线程被唤醒,从内核模式返回用户模式,再返回托管代码。

性能分析

1.        当客户端发起一个I/O请求时,线程池会创建一个线程,发起I/O请求后,线程会阻塞并等待响应。当客户端有多个I/O请求时,线程池不得不创建多个线程,这些线程都会阻塞。

2.        当I/O响应请求时,多个线程被解锁,开始执行。这时,由于CPU内核数量限制,CPU*执行频繁的上下文切换,这进一步损害了性能。

异步I/O操作

概述

异步执行的I/O限制的操作,允许将任务交由硬件设备处理,期间不占用线程和CPU资源。

各种I/O操作的结果由线程池来处理,因此线程池仍然扮演重要的角色。

执行步骤

1.        程序通过FileStream对象来打开磁盘文件,然后调用ReadAsync方法(内部调用Win32 ReadFile函数),从文件中读取数据。这时,线程从托管代码转变为本机/用户模式代码。

2.        Win32 ReadFile函数生成一个I/O请求包(IRP),并传递给Windows内核。

3.        Windows内核将IRP传送给I/O硬件设备驱动程序的IRP队列。

4.        线程立即从内核模式返回用户模式,再返回托管代码。这时FileStream的ReadAsync方法返回一个Task<Int32>对象。

5.        硬件设备执行I/O操作。

6.        在硬件设备完成I/O操作后,将完成的IRP放到线程池队列中。

7.        将来某个时间,一个线程池线程会提取完成的IRP,并访问读取到的数据。

性能分析

1.        在硬件设备执行I/O操作期间,线程不阻塞,可以避免线程池创建更多的线程。

2.        硬件设备执行I/O操作后,它的响应也会进入线程池队列,由线程池分配线程进行处理,可以更合理地利用线程,避免CPU的频繁上下文切换。

3.        异步I/O将线程控制在少数几个,可以节省内存空间,减少每次垃圾回收的时间,增强调试性能。

4.        异步I/O可以并发执行,减少处理时间。