异步磁盘 I / O 出现在 Windows NT、 Windows 2000 和 Windows XP 上同步

 本文摘自(support.microsoft.com/kb/156932)
Microsoft Windows NT、 Windows 2000 和 Windows XP 上的文件 I / O 可以是同步还是异步。 I / O 的默认行为是同步: 一个 I / O 函数调用,并返回 I / O 完成时。 异步 I / O 另一方面,允许一个 I / O 函数立即,返回返回给调用方的执行,但 I / O 不则认为某些将来之前已完成。 当 I / O 完成时,操作系统将通知调用方。 或者,调用方可以确定使用操作系统的服务的未完成的 I / O 操作的状态。

异步 I / O 的优点是调用者具有执行其他操作或在 I / O 操作在完成时发出更多的请求。 为重叠 I / O 经常用于异步 I / O 和非重叠的 I / O 使用同步 I / O 术语。 本文使用条款异步和同步的 Windows NT 下的 I / O 操作。 本文假定读者已了某些熟悉如 CreateFile,ReadFile,WriteFile 文件 I / O 函数。

经常,异步 I / O 操作行为只同步 I / O 本文讨论在更高版本的部分使 I / O 操作完成同步的某些条件。 调用方具有背景工作没有时间,因为 I / O 完成之前,不返回 I / O 函数。

同步和异步 I / O 与多个函数。 本文使用 ReadFile 和 WriteFile 作为示例 ; 很好的替代方法将 ReadFileEx 和 WriteFileEx。 虽然本文将专门讨论只有磁盘 I / O,原则的许多可用于其他类型的 I / O 如串行 I / O 或网络 I / O。

注意 : 由于 Windows 95 不支持异步 I / O 磁盘设备上 (尽管它实现其他类型的 I / O 设备),本文中不包含它的行为。

设置异步 I / O

在打开文件时,必须在 CreateFile 指定 FILE_FLAG_OVERLAPPED 标志。 此标记允许的文件以异步执行 I / O 操作。 下面是一个示例:

HANDLE hFile;

hFile = CreateFile(szFileName,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);

if (hFile == INVALID_HANDLE_VALUE)
ErrorOpeningFile();

被异步 I / O 的编码,因为系统保留进行操作的同步,如果它需要的权利时要小心。 因此,最好如果您编写程序正确处理可能会完成同步或异步 I / O 操作。 代码示例演示了此注意事项。

有很多事情程序可以执行时等待完成的异步操作,例如队列附加的操作或执行后台工作。 是例如下面的代码正确处理重叠和非重叠完成读取操作。 它不执行任何操作多个等待完成未完成 I / O:

if (!ReadFile(hFile,
pDataBuf,
dwSizeOfBuffer,
&NumberOfBytesRead,
&osReadOperation )
{
if (GetLastError() != ERROR_IO_PENDING)
{
// Some other error occurred while reading the file.
ErrorReadingFile();
ExitProcess(0);
}
else
// Operation has been queued and
// will complete in the future.
fOverlapped = TRUE;
}
else
// Operation has completed immediately.
fOverlapped = FALSE;

if (fOverlapped)
{
// Wait for the operation to complete before continuing.
// You could do some background work if you wanted to.
if (GetOverlappedResult( hFile,
&osReadOperation,
&NumberOfBytesTransferred,
TRUE))
ReadHasCompleted(NumberOfBytesTransferred);
else
// Operation has completed, but it failed.
ErrorReadingFile();
}
else
ReadHasCompleted(NumberOfBytesRead);

注意 & NumberOfBytesRead 传入 ReadFile 与不同 & NumberOfBytesTransferred 传入 GetOverlappedResult。 如果操作已成为异步,则将使用 GetOverlappedResult 确定其完成后,在操作中传输的字节实际的数。 在和 NumberOfBytesRead 传入 ReadFile 没有意义。

如果在另一方面的操作然后立即,完成和 NumberOfBytesRead 传入则 ReadFile 是有效的读取的字节数。 在这种情况下忽略传递到 ReadFile OVERLAPPED 结构 ; 不要将它使用与 GetOverlappedResult 或 WaitForSingleObject。

与异步操作的另一个 caveat 是您必须不使用的 OVERLAPPED 结构直到完成挂起的操作。 换句话说,如果三个未完成的 I / O 操作必须使用三个 OVERLAPPED 结构。 如果您重复使用的 OVERLAPPED 结构,则您将在 I / O 操作中收到不可预知的结果,并且您可能会遇到数据损坏。 此外,才可以在第一的次使用了 OVERLAPPED 结构或较早的操作完成后重用它,您必须正确初始化它以便没有左转移数据会影响新的操作。

相同类型的限制适用于在操作中使用的数据缓冲区中。 数据缓冲区必须不能读取或写入其相应的 I / O 操作完成之前 ; 读取或写入缓冲区可能会导致错误和损坏的数据。

异步 I / O 仍显示为同步

如果您遵循本文前面的中,说明,但是,所有 I / O 操作仍完成同步顺序发出,和任何 ReadFile 操作返回 FALSE 使用 GetLastError() 返回 ERROR _ IO _ PENDING,这意味着必须没有任何背景的工作时间。 这是为什么出现的?

有多种原因 I / O 操作完成同步即使已编码为异步操作的原因:

压缩

异步操作的一个障碍是 NTFS 压缩。 文件系统驱动程序将不访问压缩的文件以异步方式 ; 而是所有操作只是都进行同步。 这不适用于使用类似于压缩或 PKZIP 的实用工具压缩的文件。

NTFS 的加密

类似于压缩,文件加密导致系统驱动程序将异步 I / O 转换为同步。 如果文件被解密,I / O 请求都将是异步的。

扩展文件

同步完成 I / O 操作的另一个原因是其自身操作。 在 Windows NT 上任何写入到扩展其长度的文件的操作将同步。

注意 : 应用程序可以在前面提到的写操作异步通过更改进行文件的有效数据长度通过使用该 SetFileValidData 函数和然后发出一个 WriteFile。

使用 SetFileValidData (这是 Windows XP 和更高版本上可用),应用程序可以有效地扩展文件而不需要为这些零填充的性能损失。

因为 NTFS 文件系统不会零填充到有效数据长度 (VDL) 由 SetFileValidData,此函数定义的数据具有安全意义的文件可能为分配了其他文件先前占用的群集。 因此,SetFileValidData 要求调用方具有新的 SeManageVolumePrivilege 启用 (默认情况下, 此分配管理员)。 Microsoft 建议 ISV 仔细考虑使用该函数的含义。

缓存

大多数的 I / O 驱动程序 (磁盘、 Communications,及其他) 具有特殊的 Case 代码位置,如果 I / O 请求完成"立即",将完成此操作,并了 ReadFile 或 WriteFile 函数将返回 TRUE。 所有方式这些类型的操作将显示为同步中。 了磁盘设备通常,I / O 请求可以完成"立即"时,数据缓存在内存中。

数据不在缓存中

缓存方案可对您,但是,如果数据文件不在缓存中。 Windows NT 缓存实现在内部使用文件映射。 内存管理器在 Windows NT 中不提供的异步页面错误机制,来管理缓存管理器使用的文件映射。 在缓存管理器可以但是,验证所请求的页是否在内存,因此如果您发出的异步的缓存的读取并且页面不在内存中,文件系统驱动程序假定您不希望您阻止的线程,并 将由有限的辅助线程池处理请求。 使用仍然挂起读取您 ReadFile 调用之后将给您的程序返回控制权。

这正常为少数的请求,但是由于工作线程池是有限制 (三当前个 16MB 的可系统上),将仍然只有几个请求排队磁盘驱动程序在特定时间。 如果您发出大量 I / O 操作未在缓存中的数据,缓存管理器以及管理器会达到饱和的内存和您的请求进行同步。

缓存管理器可以还影响的行为根据是否按顺序或随机访问文件。 按顺序访问文件时,将最出现缓存的优点。 CreateFile 调用中的 FILE_FLAG_SEQUENTIAL_SCAN 标志将优化缓存的此类访问权限。 但是,如果您访问以随机的方式的文件,使用 FILE_FLAG_RANDOM_ACCESS 标志 CreateFile 中以指示缓存管理器在优化对随机访问其行为。

不使用缓存

FILE_FLAG_NO_BUFFERING 标志具有对文件系统为异步操作的行为大多数的效果。 这是最佳方法,以保证 I / O 请求是实际异步。 它指示文件系统根本不使用任何缓存机制。

警告 : 有使用此标志与数据缓冲区对齐和设备的扇区大小有一些限制。 请参阅有关正确使用此标志 CreateFile 函数文档中的函数参考。

SAMPLE 代码

从 Microsoft 下载中心下载下列文件有:

Asynczip.exe (http://download.microsoft.com/download/platformsdk/sample/3/nt4/en-us/asynczip.exe)

有关如何下载 Microsoft 支持文件单击下面的文章编号,以查看 Microsoft 知识库中的相应:

119591 (http://support.microsoft.com/kb/119591/EN-US/ ) 如何从联机服务获取 Microsoft 支持文件

Microsoft 扫描病毒此文件。 Microsoft 使用最新的病毒检测软件在发布该文件的日期中获得的。 该文件存储在安全性得到增强有助于防止任何未经授权的更改对文件的服务器上。 与本文关联的代码示例演示标志和讨论的功能的使用。 该代码是作为控制台应用程序运行在 Windows NT 上。 以下命令行开关控制其行为:

Asynchio
Usage: asynchio [options]

Options:
/fFilePattern Files to use for I/O.
/s Specifies synchronous operation.
/n Specifies that no buffering should be used
/r Use FILE_FLAG_RANDOM_ACCESS
/l Use FILE_FLAG_SEQUENTIAL_SCAN
/o### Issue ### operations
/e First read entire file, then issue smaller reads
/? Display this usage message.
示例: asynchio /f*.bmp n

此程序的默认操作是异步的缓冲操作。 默认,请求 500 个 I / O 操作。

真实世界上测试结果

以下是示例代码中的某些测试结果。 数字的量不重要此处并不同计算机,但与彼此的数字的关系照亮常规标记对性能的影响。

您可能希望看到与以下内容类似的结果:

  • 测试 1
    Asynchronous, unbuffered I/O:  asynchio /f*.dat /n

    Operations completed out of the order in which they were requested.
    500 requests queued in 0.224264 seconds.
    500 requests completed in 4.982481 seconds.
    此测试演示上述的程序快速发出 500 个 I / O 请求,并有大量时间执行其他操作或发出多个请求。
  • 测试 2
    Synchronous, unbuffered I/O: asynchio /f*.dat /s /n

    Operations completed in the order issued.
    500 requests queued and completed in 4.495806 seconds.
    此测试演示了此程序花费 4.495880 秒调用 ReadFile 完成其操作,而测试 1 花费只 0.224264 秒发出相同的请求。 在测试 2,没有"额外的时间,程序执行任何后台工作。
  • 测试 3
    Asynchronous, buffered I/O: asynchio /f*.dat

    Operations completed in the order issued.
    500 requests issued and completed in 0.251670 seconds.
    此测试演示缓存的同步性质。 所有显示已发放给并在 0.251670 秒内完成。 换句话说,已同步完成异步请求。 在缓存中数据时,此测试还演示了缓存管理器的高性能。
  • 测试 4
    Synchronous, buffered I/O: asynchio /f*.dat /s

    Operations completed in the order issued.
    500 requests and completed in 0.217011 seconds.
  • 此测试演示与测试 3 一样的结果。 请注意同步读取从缓存完成有点快于异步读取缓存中。 在缓存中数据时,此测试还演示了缓存管理器的高性能。

 

结论

您可以决定哪种方法是最佳的因为其取决于该类型、 大小和程序执行的工序的数量。

未指定任何特殊标志 CreateFile 的默认文件访问是同步和缓存的操作。

注意 : 您得某些自动异步行为在此模式下因为文件系统驱动程序会预测异步预读和异步惰性写入修改数据。 尽管这不会使应用程序 [ASCII 146] s I / O 异步,对于大量大多数简单的应用程序的理想情况是。

如果在另一方面,您的应用程序不是简单的必须执行一些分析和性能监控来确定最佳方法类似于本文前面所示的测试。 分析时花费了 ReadFile 或 WriteFile 函数,然后比较时间的实际的 I / O 操作完成这一次非常有用。 如果大部分时间所花费的实际发出 I / O,然后在 I / O 是在完成同步。 但是,如果所用的时间颁发证书的 I / O 请求是相对较小与的时间 I / O 操作完成,然后操作将在异步处理。 本文前面提及的示例代码使用 QueryPerformanceCounter 函数为其自身内部分析。

性能监视有助于确定程序在磁盘和缓存的使用效率。 跟踪任何缓存对象的性能计数器将指示缓存管理器的性能。 跟踪物理磁盘或逻辑磁盘的对象的性能计数器将指示磁盘系统的性能。

有几个实用程序有助于性能监视的 ; PerfMon 和 diskperf 是特别有用。 系统磁盘系统的性能收集数据,您必须首先发出 diskperf-y 命令。 在发出命令后,您必须重新启动系统以启动数据集。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值