6

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

  1. NetworkStream 来自持续侦听传入消息的 TcpClient。
  2. 我不想用标准的 NetworkStream.Read() 阻塞线程。这需要扩展。我只是假设 Read() 块,因为这是这类类的非常标准的行为,并且类上有一个 ReadTimeout 属性。
  3. 我不确定 BinaryFormatter 是否只使用 Read() 或者它是否在后台为我做了一些异步的东西。我的猜测是否定的。
  4. TcpClient 需要获取一条消息,将其读到最后,然后返回侦听消息。

因此,似乎有太多方法可以给这只猫剥皮,我不确定哪种方法最有效。我是否:

只需使用 BinaryFormatter 来读取 NetworkStream?

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

或者用新的 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);
}

或者别的什么?

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

[注:以上均为伪代码,以示例为例]

4

4 回答 4

5

第一种方法遇到了大流的问题。如果您要发送大数据,该代码将导致应用程序出现内存不足异常。

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

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

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

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
    }
}
于 2013-01-08T20:40:04.920 回答
2

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

不过,它会更慢。异步具有在基准测试中很容易检测到的开销。如果您不需要选项 2,则首选使用选项 1。

于 2013-01-08T20:45:10.467 回答
2

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

于 2013-01-08T20:38:16.760 回答
1

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

于 2013-01-08T21:55:56.450 回答