是否可以强制由 FileStream.BeginRead 启动的异步读取操作提前完成,而不会出现错误?

发布于 2024-12-02 00:03:56 字数 996 浏览 6 评论 0 原文

首先,EndRead 的文档没有明确指出由 BeginRead 发起的异步读取操作是原子的或不可中断的。

问题

是否可以中断异步读取操作由 FileStream.BeginRead 启动,以便它在填充缓冲区之前完成,返回到目前为止读入缓冲区的字节数,还是全有或全无操作?

换句话说,是否有一些像“Cancel_IO”这样的方法,我可以调用,这样当我调用 EndRead 时,它不会等待所有可能的字节被读取,而是由于读取被取消而更早返回?

背景

我已经阅读了 FileStream、BeginRead 和 EndRead 的文档。 EndRead 没有任何能够触发操作过早完成、返回部分满缓冲区的重载。我感兴趣的是是否有人可以确认或否认 Windows 操作系统的 API (Win32) 或磁盘驱动程序 API 中是否存在某种方法,该方法可能导致 FileStream.BeginRead 启动的操作在 EndRead 为时提前完成叫。我所说的“早期”是指在填充整个请求的缓冲区长度之前,没有错误。

用例

为了缺乏想象力,假设文件位于网络共享上,并且网络有时可能会经历极度缓慢的情况,因此触发通用 1MB 缓冲操作的提前完成将是实用且最佳的,以便在恢复新的 1MB 缓冲操作之前检索几个字节进行处理。

这些“几个字节”可用于启动许多计算密集型内存资源的构造,这些资源可以在允许缓冲完成时构造。

关于文档

请注意,BeginRead 的文档没有明确声明异步操作是原子的或不可中断的。它所提到的是,如果发生“错误”,在调用 EndRead 之前您不会知道。这并不排除发生某些其他事件(不是错误)的可能性,这些事件会导致 EndRead 返回小于请求数量的字节数,无论如何它总是这样做。

例如,“文件结尾”和“缓冲区已满”可以被视为异步读取操作的两个“自然”中断,这会导致它返回的字节数少于请求的字节数,而不会出现错误。我正在寻找“人为”中断的可能性,这也会导致 EndRead 在 EOF 之前和缓冲区已满之前成功返回读入缓冲区的字节数。

First of all, the documentation for EndRead does NOT explicitly say that an asynchronous read operation initiated by BeginRead is atomic or uninterruptable.

The Question

Is it possible to interrupt an asynchronous read operation started by FileStream.BeginRead, so that it finishes before filling the buffer, returning the number of bytes read into the buffer so far, or is it an all or nothing operation?

In other words, is there some method like "Cancel_IO", that I can call, such that when I call EndRead, instead of waiting for all possible bytes to be read, it returns earlier as as result of the read being cancelled?

Background

I've read the documentation of FileStream, BeginRead, and EndRead. EndRead does not have any overloads that are capable of triggering premature completion of the operation, returning a partially full buffer. I'm interested in whether anyone can confirm or deny the existence of a method in the Windows Operating System's API (Win32), or perhaps of a disk driver API, that could cause an operation initiated by FileStream.BeginRead to finish early when EndRead is called. By "early", I mean before filling the entire requested buffer length, without an error.

Use Case

For the sake of the unimaginative, assume the file is on a network share, and the network may sometimes experience extreme slow-downs, such that triggering the early completion of a generic 1MB buffering operation would be practical and optimal, in order to retrieve a few bytes for processing before resuming a new 1MB buffering operation.

Those "few bytes", could be used to initiate the construction of a number of computationally-intensive in-memory resources, which could be constructed while the buffering is allowed to finish.

About the Documentation

Note that the documentation of BeginRead does not explicitly state that the asynchronous operation is atomic or is uninterruptable. All it mentions is that if an "error" occurs, you won't know about it until EndRead is called. This does not preclude the possibility that some other event, which is not an error, could occur that would cause EndRead to return some number of bytes less than the number requested, which it does all the time anyway.

For example, "end of file" and "buffer full" can be though of as the two "natural" interruptions of an asynchronous read operation, which cause it to return less than the number of bytes requested, without error. I'm looking for "artificial" interruption possibilities, which would also cause EndRead to successfully return the number of bytes read into the buffer, before the EOF and before the buffer is full.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

为人所爱 2024-12-09 00:03:56

文档明确指出:必须使用此 IAsyncResult 调用 EndRead找出读取了多少字节。另一方面 EndRead 正在阻塞线程,直到读操作完成。所以,看起来读操作是原子的。

这对我来说是合乎逻辑的,因为你的场景有一些实际用途。如果有价值的信息存储在正在读取的文件的一部分中,那么您始终可以以较小的部分读取它。

Documentation explicitly says that: EndRead must be called with this IAsyncResult to find out how many bytes were read. On the other hand EndRead is blocking thread until read operation is completed. So, seems like read operation is atomic.

This is logical to me, since your scenario have a little of practical usage. If valuable information is stored in part of file being read, then you can always read it in smaller portions.

薄暮涼年 2024-12-09 00:03:56

我在 Windows 同步和异步文档中读到了一些内容I/O 可能会起作用,但这将是一个后果不确定的技巧。

“如果过早释放句柄,ReadFile 或 WriteFile 可能会
错误地报告 I/O 操作已完成。”

由于 .NET BeginRead 方法最终基于 Win32 ReadFile 方法,因此获取并过早释放句柄可能会完成我想要做的事情。这样做的后果将需要研究

还提到“要取消所有挂起的异步 I/O 操作,请使用:CancelIoCancelIoEx",但这些似乎会失败地取消整个操作(ERROR_OPERATION_ABORTED)。我不确定读取的任何字节是否已经写入缓冲区,即使它们是,我不知道有多少个已成功写入。我想知道是否有一种方法可以欺骗底层系统,使其认为它突然到达文件或流的末尾......

我还看到“SetCommTimeouts" 方法有一些有趣的结果,在特别是围绕“COMMTIMEOUTS 结构的“ReadIntervalTimeout”成员,它声明:

“如果任意两个字节到达的间隔超过这个
量,ReadFile 操作已完成,所有缓冲数据均已完成
返回。”

这似乎很有希望...

无论如何,我可以取消挂起的异步 I/O 这一事实就很有用。我实际上可以使用缓冲统计信息和开始时间来计算,是否值得取消异步 I/O读取并重新发出所需数据块的较小读取,或者是否最好等待操作完成,这取决于计算出的流的平均速度,以及它距离完成有多近(基于。它是计算/预测的进度值)和预期完成时间,根据获取所需数据块的相对效用进行加权。

I read something in the documentation for windows synchronous and asynchronous I/O that may do the trick, but it would be a trick with uncertain consequences.

"If the handle is deallocated prematurely, ReadFile or WriteFile may
incorrectly report that the I/O operation is complete."

Since the .NET BeginRead method is ultimately based on the Win32 ReadFile method, then acquiring and prematurely deallocating the handle may accomplish what I'm trying to do. The consequences of this will need researched.

It also mentions "To cancel all pending asynchronous I/O operations, use either: CancelIo or CancelIoEx", but those appears to cancel entire operations with failure (ERROR_OPERATION_ABORTED). I'm not sure whether any bytes read would have already been written to the buffer, and even if they were, one would not know how many were successfully written. I wonder if there's a way to trick the underlying system into thinking it has suddenly reached the end of the file or stream...

I also see that the "SetCommTimeouts" method has some interesting results, in particular surrounding the "COMMTIMEOUTS Structure's" "ReadIntervalTimeout" member, which claims that:

"If the interval between the arrival of any two bytes exceeds this
amount, the ReadFile operation is completed and any buffered data is
returned."

That seems promising...

In any case, the mere fact that I can cancel pending asynchronous I/O is useful. I could actually compute, using buffering stats and start times, whether it would be worth it to cancel the asynchronous read and re-issue a smaller read of the desired data chunk or whether it would be better to just wait for the operation to complete. It would depend on the calculated average speed of the stream, and how close it is to completion (based on it's computed/predicted progress value) and expected completion time, weighted against the relative utility of obtaining the desired data chunk.

单身狗的梦 2024-12-09 00:03:56

不;没有 API 可以做到这一点。

关闭手柄是一个古老的技巧——它的作用可以追溯到新台币时代。但是,它会导致句柄上的所有未完成操作完成时出现错误。

取消也有类似的问题 - 请注意 CancelIoEx 在您的平台上可能不可用。

SetCommTimeouts 不是一个选项,因为它仅适用于串行端口和其他通信设备句柄。

历史上,取消一直是编写设备驱动程序中最困难的部分之一。如今,内核在 XP 中内置了取消安全队列支持(可向后移植到 2K),而且更加容易。但很多司机(尤其是老司机)无论如何都会忽略取消(这是合法的)。

我建议在更高的抽象级别实现“取消”:关闭句柄或允许操作完成,并忽略结果。

No; there is no API that can do this.

Closing the handle is an old trick - it works way back to the NT days. However, it causes all outstanding operations on the handle to complete with an error.

Cancelling has similar problems - and note that CancelIoEx may not be available on your platform.

SetCommTimeouts is not an option, since it only works on serial ports and other communication device handles.

Cancellation has historically been one of the most difficult parts of writing a device driver. These days, the kernel has Cancel-Safe Queue support built-in to XP (back-portable to 2K), and it's a lot easier. But a lot of drivers (especially older drivers) just ignore cancellation anyway (which is legal).

I recommend implementing a "cancel" at a higher level of abstraction: close the handle or allow the operation to complete, and ignore the result.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文