从NetworkStream中读取BinaryFormatter序列化对象的最有效方法



我有一个应用程序,是通过套接字连接发送不同大小的可序列化对象,我希望它是尽可能可扩展的。也可能有几十个甚至几百个连接。

  1. NetworkStream来自TcpClient,该TcpClient持续侦听传入消息。
  2. 我不想用标准的NetworkStream.Read()阻塞线程。这需要扩大规模。我只是假设Read()阻塞了,因为这是这种类的标准行为,并且类上有一个ReadTimeout属性。
  3. 我不确定BinaryFormatter是否只是使用Read(),或者它是否为我做了一些Async的东西。我猜没有。
  4. TcpClient需要得到一个消息,读到最后,然后返回监听消息。

所以,似乎有太多的方法来剥掉这只猫的皮,我不确定什么才是最有效的。我:

简单地使用BinaryFormatter来读取NetworkStream?

var netStream = client.GetStream();
var formatter = new BinaryFormatter();
var obj = formatter.Deserialize(netStream);

OR使用新的async/await内容:

using(var ms = new MemoryStream()) 
{
   var netStream = client.GetStream();
   var buffer = new byte[1028];
   int bytesRead;
   while((bytesRead = await netStream.ReadAsync(buffer, 0, buffer.length)) > 0) {
      ms.Write(buffer, 0, buffer.Length);
   }
   var formatter = new BinaryFormatter();
   var obj = formatter.Deserialize(ms);
}

与上面类似,只是利用了新的CopyToAsync方法:

using(var ms = new MemoryStream()) 
{
   var netStream = client.GetStream();
   await netStream.CopyToAsync(ms); //4096 default buffer.
   var formatter = new BinaryFormatter();
   var obj = formatter.Deserialize(ms);
}

还是还有什么?

我正在寻找提供最大可扩展性/效率的答案。

[注:以上均为psuedo代码,仅作为示例]

第一种方法在处理大数据流时遇到了问题。如果你要发送大数据,这些代码会导致应用程序出现内存不足的异常。

第二种方法看起来很好——它是异步的(意味着你不需要使用一些有价值的线程来等待读取完成),并且它使用数据块(这是你应该如何处理流的)。

所以选择第二种选择,也许稍微修改一下——一次只反序列化数据块,不要读取整个数据(除非你绝对确定流的长度)。

这就是我的想法(伪代码)

using (var networkStream = client.GetStream()) //get access to stream
{
    while(!networkStream.EndOfStream) //still has some data
    {
        var buffer = new byte[1234]; //get a buffer
        await SourceStream.ReadAsync(result, 0, buffer); //read from network there
        //om nom nom buffer     
        Foo obj;
        using(var ms = new MemoryStream()) //process just one chunk
        {
             ms.Write(buffer, 0, buffer.Length);
             var formatter = new BinaryFormatter();
             obj = formatter.Deserialize(ms);   //desserialise the object        
        } // dispose memory
        //async send obj up for further processing
    }
}

async/await将允许您在等待资源时更少地阻塞线程,因此通常它将比线程阻塞版本具有更好的伸缩性。

如果有数百个并发操作在运行

Async将具有更好的伸缩性。

但是,它将逐渐变慢。Async的开销在基准测试中很容易检测到。如果不需要选项2,建议使用选项1

我认为值得一提的是,从客户端角度来看,异步与同步是有区别的。如果你异步…每个人通常都会经历相同的响应时间。因此,如果您的所有请求都是密集的,那么每个人都会意识到响应时间较慢。使用同步请求,简单请求的用户将得到更快的处理,因为它们不会被其他用户阻塞。然而,如果你在一个同步环境中有许多同时的请求,最终可能会阻塞所有的线程,请求将得不到响应。

相关内容

  • 没有找到相关文章

最新更新