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

时间:2013-01-08 20:22:45

标签: c# .net-4.5 async-await networkstream c#-5.0

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

  1. NetworkStream来自一个持续侦听传入消息的TcpClient。
  2. 我不想用标准的NetworkStream.Read()来阻塞一个线程。这需要扩展。我只是假设Read()块,因为这是这类类的非常标准的行为,并且在类上有一个ReadTimeout属性。
  3. 我不确定BinaryFormatter是否只使用Read(),或者它是否为我做了一些Async的东西。我的猜测是否定的。
  4. TcpClient需要收到一条消息,将其读取到最后,然后返回收听消息。
  5. 所以似乎有很多方法可以让这只猫受到伤害,而且我不确定什么才是最有效的。我:

    只需使用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);
    }
    

    OR 与上述类似,只利用新的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代码,作为示例给出]

4 个答案:

答案 0 :(得分:5)

第一种方法遇到了大流的问题。如果您要发送大数据,那么该代码会使应用程序因内存不足而异常。

第二种方法看起来非常好 - 它是异步的(意味着你不使用一些有价值的线程来等待读取完成)并且它使用数据块(这就是你应该如何使用流)。 / p>

所以选择第二个选项,可能稍作修改 - 一次只反序列化大块数据,不要读取整个内容(除非你绝对确定流长度)。

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

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
    }
}

答案 1 :(得分:2)

async / await将允许您在等待资源时更少地阻塞线程,因此通常它会比线程阻塞版本更好地扩展。

答案 2 :(得分:2)

如果数百个并发操作正在运行,Async将更好地扩展。

但是,它会连续慢一些。 Async具有在基准测试中容易检测到的开销。如果您没有需要选项2,请选择使用选项1.

答案 3 :(得分:1)

我认为值得一提的是,从客户端角度来看,异步与同步之间存在差异。如果你去异步......每个人都会经历相同的响应时间。因此,如果您的所有请求都很密集,那么每个人都会意识使用同步请求,具有简单请求的用户将被更快地处理,因为他们不会被其他用户阻止。但是,如果在同步环境中有多个并发请求,最终可能会阻止所有线程,并且请求将无法获得响应。