【问题标题】:Asynchronous BinaryReader and BinaryWriter in .Net?.Net 中的异步 BinaryReader 和 BinaryWriter?
【发布时间】:2012-04-25 12:11:06
【问题描述】:

我想异步读取和写入字节和结构化值类型,而不必担心解码器和字节移位:有什么东西可以让我这样做吗?

【问题讨论】:

  • Stream.BeginRead 等怎么样?
  • 这是在 Stream 上,而不是 BinaryReader 和 BinaryWriter。
  • 你想读/写字节;为此,您不需要BinaryReader/BinaryWriter - 他们确实对此毫无帮助。
  • 我的猜测是带有异步方法的 BinaryReader/BinaryWriter 对于大多数情况来说过于精细,性能会因此受到影响。
  • Couldn't a ReadInt16() : Async 在阅读器上,只需从底层流中获取 512 块数组?为什么只需要从流中读取最少量的内容 - 在这种情况下,它不会严重影响性能,不是吗?

标签: .net f#


【解决方案1】:

BinaryReaderBinaryWriter 不可能。您可以同时从底层BaseStream 读取,但documentation 声明如下:

在读取或使用 BinaryReader 时使用底层流可能会导致数据丢失和损坏。例如,可能会多次读取相同的字节,可能会跳过字节,或者字符读取可能变得不可预测。

因此,唯一的方法是推出您自己的实现。但这样做的好处是有争议的。来自微软的 Marco Greg 在博客文章Should I expose asynchronous wrappers for synchronous methods? 中添加了以下评论:

Jon:BinaryReader/Writer 没有 XxxAsync 方法的原因是这些类型的方法通常只从先前打开的基础流中读取/写入很少的字节。在实践中,数据经常被缓存,从底层源获取数据所需的时间通常非常短,因此不值得异步执行。

值得注意的是,这些类型的某些方法在某些情况下可能会传输大量数据(例如 ReadString)。进一步来说,这些方法的异步版本可能会添加也可能不会添加,但不太可能在不久的将来发生。

一般来说,如果您正在读取的数据量很大(至少数百或数千字节),或者您是第一次访问资源(例如第一次读取),您应该只考虑异步 IO 方法即使您正在读取一个字节,也可能需要从文件中启动磁盘)。

这听起来很合理。如果您确实需要解决方案,除了滚动您自己的BinaryReader/BinaryWriter 之外,还有几种解决方法。您可以在单独的线程中运行它(这可能效率低下),或者如果您愿意更改文件格式或有线协议,您可以使用此模式(伪代码):

//read packet length
await stream.ReadAsync(buffer);
var packetLength=convertToInt(buffer);

//read complete packet asynchronously
await stream.ReadAsync(buffer,packetLength);

//process packet with BinaryReader
using(var br=new BinaryReader(new MemoryStream(buffer))
{
  //...
}

请注意,这种模式仅在整个缓冲区很容易装入内存并且性能可能会受到影响时才有用。

【讨论】:

    【解决方案2】:

    您可以使用FileStream,确保正确调用构造函数,以便它启用异步并有足够大的缓冲区。

    var buffer = new byte[2048];
    
    using var r = new FileStream(
                      Path,
                      FileMode.Open, 
                      FileAccess.ReadWrite, 
                      FileShare.None, 
                      2048000, 
                      FileOptions.Asynchronous);
    
    await r.ReadAsync(buffer, 0, 2048);
    await r.Writesync(buffer);
    

    现在您有了一个字节数组,您可以通过三个选项将它们转换为对象:

    • 使用BitConverter
    • 使用BinaryFormatterMemoryStream
    • 编写您自己的自定义逻辑

    【讨论】:

      【解决方案3】:

      我已经创建了这些类的异步版本:https://github.com/ronnieoverby/AsyncBinaryReaderWriter

      示例用法:

      async Task Main()
      {
          using var ms = new MemoryStream();
          using var writer = new AsyncBinaryWriter(ms);
          await writer.WriteAsync("today is: ");
          await writer.WriteAsync(DateTime.Today.Ticks);
          await writer.FlushAsync();
      
          ms.Position = 0;
      
          using var reader = new AsyncBinaryReader(ms);
          var preamble = await reader.ReadStringAsync();
          var payload = new DateTime(await reader.ReadInt64Async());
      
          Console.WriteLine(preamble + payload);
      }
      

      BCL 二进制读取器/写入器类中存在的所有相同读取/写入方法都存在。

      【讨论】:

      猜你喜欢
      • 2016-05-26
      • 2018-08-21
      • 1970-01-01
      • 1970-01-01
      • 2016-07-27
      • 1970-01-01
      • 1970-01-01
      • 2020-02-20
      • 1970-01-01
      相关资源
      最近更新 更多