【问题标题】:Method to provide an efficient callback to ReadFile向 ReadFile 提供有效回调的方法
【发布时间】:2017-12-22 15:05:17
【问题描述】:

在我的工作线程中,我需要能够在用户输入时停止长文件操作。我目前的方法是在一个小缓冲区上重复调用ReadFile,然后在每次迭代后调用回调函数。像这样的:

//Error checks are omitted for brevity

for(;;)
{
    ::ReadFile(hFile, SmallBuffer, nSizeOfSmallBuffer, nBytesRead);

    if(!pfnCallbackProc())
    {
        //Abort
        break;
    }
}

BOOL callbackProc()
{
    return ::WaitForSingleObject(hStopEvent, 0) == WAIT_OBJECT_0;
}

此方法有效。但是,当我进行基准测试以查看它对一个简单调用的运行速度有多慢时:

::ReadFile(hFile, FullBuffer, nSizeOfFullBuffer, nBytesRead);

SSD(随机存取磁盘)上的差异并不大,但当我从旋转驱动器读取大文件时,差异会变得非常明显。例如,使用单个ReadFile 读取一个 4GB 文件大约需要 32 秒,使用我的方法和上面的回调大约需要 46 秒。 (据我所知,由于在旋转磁盘上反复调用 ReadFile,会导致更大的延迟。)

所以我想知道是否有更有效的方法来做到这一点?

【问题讨论】:

  • 当您标记 winapi 时,请阅读 MSDN 上的 I/O Completion Ports msdn.microsoft.com/en-us/library/windows/desktop/… 也重叠 IO:msdn.microsoft.com/en-us/library/windows/desktop/…
  • 唯一的办法就是降低循环的迭代量。一种方法是增加您读取的缓冲区大小。您只需要尝试多种不同的读取缓冲区大小,这样您就可以获得可接受的性能,同时仍然能够满足程序的要求(例如能够在足够短的时间内取消读取)。跨度>
  • 在您的程序运行期间(不是设计时,但我的意思是在您实际发布的应用程序中)花哨并对其进行测量,并将尺寸调整为尽可能大,但仍然具有响应性。跨度>
  • 如果您想停止阅读,只需在文件中调用CancelIoEx
  • 什么是nSizeOfSmallBuffer

标签: c++ winapi readfile hard-drive


【解决方案1】:

可能最明显的可能性是使用ReadFileEx 进行重叠读取。然后你可以使用CancelIo 在必要时/如果需要取消 I/O。

由于这是重叠的,您可以直接从父线程调用它,而不是创建一个专用于 I/O 的线程。主要要求是调用线程在准备好处理来自重叠 I/O 的反馈时进入警报等待状态。在父线程使用GetMessage 循环的典型情况下,您可以将其更改为使用MsgWaitForMultipleObjectsEx。这使您可以继续检索消息,但也可以进入警报等待状态,因此您传递给 ReadFileEx 的回调也可以被调用。

【讨论】:

  • 确实ReadFileReadFileEx 都允许异步读取。不同 - ReadFile 使用 IOCP,而 ReadFileEx 仅使用 apc 完成
  • @RbMm:是的,它们都支持重叠 I/O。但他也要求高效——至少在我测试它们时,ReadFileEx 在这方面具有相当显着的优势。也就是说,我会公开承认我的测试并没有涵盖所有可能的情况,也不清楚他愿意接受多少减速,所以重叠的 ReadFile 可能就足够了(我记得,代码它有点简单)。
  • 基本上如果我们想停止(取消)读取操作,我们也可以从另一个线程调用CancelIoEx。所以我们甚至不需要文件的异步 io。存在不同的方式,并且取决于细节,一种或另一种可能更有效
  • 谢谢你们。这听起来很合理。以及如何获取文件读取的进度,是通过调用GetOverlappedResult 并将bWait 设置为FALSE 吗?
  • @c00000fd - 不可能获得 single 文件读取的进度。 GetOverlappedResult 什么都没有给你,因为 IO_STATUS_BLOCK 在 io 完成后填充。如果想要进步 - 只有很多小读物。无论如何-您是否尝试在单个缓冲区中读取 4gb ?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多