是流.读取异步和流.WriteAsync应该在返回之前或操作完成之后同步更改游标位置

本文关键字:操作 之后 同步 位置 游标 异步 读取 WriteAsync 返回 是流 | 更新日期: 2023-09-27 17:50:38

我一直在尝试实现一个支持ReadAsyncWriteAsyncStream,并且考虑到文档的稀疏性,我正在努力理解如何正确地这样做。具体来说,与流的游标位置有关。关于旧的BeginRead函数,这里和这里都提出了类似的问题。该函数的文档似乎表明,在任何挂起的异步操作完成之前,不应该再次调用BeginRead

考虑到BeginRead现在已被弃用不再推荐用于新开发,Stream可能已经进行了重大更改以实现新的Async函数,事情再次变得不清楚。(编辑:通常这种警告意味着新函数是直接实现的,旧函数调用新函数,只是为了向后兼容而存在,但这似乎不是这里的情况)。

ReadAsyncWriteAsync函数的定义是,它们不像Win32对应的函数那样采取所需的读/写流位置(在我看来是一个非常糟糕的设计选择),而是依赖于流实现所持有的当前位置。如果满足以下两个条件之一,这种情况很好:

  1. ReadAsyncWriteAsync必须在返回Task
  2. 之前获取当前光标位置以供操作使用,并将其更新为操作完成(或根本不更新)。
  3. 在所有之前的异步调用完成之前,不能调用ReadAsyncWriteAsync

在这两个条件之外,调用者永远无法确定读或写将发生在哪个位置,因为挂起的异步操作可能会改变任何Seek和对ReadAsyncWriteAsync的调用之间的流的位置。这两个条件都没有作为需求记录下来,所以我想知道它应该如何发挥作用。

我的白盒测试似乎表明,至少对于StreamFileStream版本,流位置异步更新,这似乎表明第二个条件(只允许一个挂起操作)仍然是必需的,但这似乎是一个严重的限制(它当然排除了任何类型的内部分散-收集实现)。

谁能提供任何权威的信息,关于旧的BeginRead限制是否仍然适用于ReadAsync ?

是流.读取异步和流.WriteAsync应该在返回之前或操作完成之后同步更改游标位置

谁能提供任何权威的信息,关于旧的BeginRead限制是否仍然适用于ReadAsync ?

同样的限制适用于BeginReadReadAsync

旧的APM方法没有被弃用。它们仍然得到充分的支持,使用它们没有任何问题。然而,async方法相当容易使用,所以文档建议使用它们。

所有这些旧类的async"重载"通常仍然由调用BeginXXXEndXXX组成,或者最多两个选项都调用共享方法(例如FileStream.BeginReadAsync)。我从未见过任何代码(在框架中或其他地方)在async之上有APM包装器方法。

因此,调用ReadAsync将导致调用BeginRead,因此任何限制都适用于两者。此外,由于Stream不是线程安全的,也没有宣称它是并发安全的(这略有不同),因此可以安全地假设您不能并发地使用async请求来淹没它。