我有一个应用程序,是通过套接字连接发送不同大小的可序列化对象,我希望它是尽可能可扩展的。也可能有几十个甚至几百个连接。
- NetworkStream来自TcpClient,该TcpClient持续侦听传入消息。
- 我不想用标准的NetworkStream.Read()阻塞线程。这需要扩大规模。我只是假设Read()阻塞了,因为这是这种类的标准行为,并且类上有一个ReadTimeout属性。
- 我不确定BinaryFormatter是否只是使用Read(),或者它是否为我做了一些Async的东西。我猜没有。
- 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);
}
还是还有什么?
我正在寻找提供最大可扩展性/效率的答案。
第一种方法在处理大数据流时遇到了问题。如果你要发送大数据,这些代码会导致应用程序出现内存不足的异常。
第二种方法看起来很好——它是异步的(意味着你不需要使用一些有价值的线程来等待读取完成),并且它使用数据块(这是你应该如何处理流的)。
所以选择第二种选择,也许稍微修改一下——一次只反序列化数据块,不要读取整个数据(除非你绝对确定流的长度)。
这就是我的想法(伪代码)
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
我认为值得一提的是,从客户端角度来看,异步与同步是有区别的。如果你异步…每个人通常都会经历相同的响应时间。因此,如果您的所有请求都是密集的,那么每个人都会意识到响应时间较慢。使用同步请求,简单请求的用户将得到更快的处理,因为它们不会被其他用户阻塞。然而,如果你在一个同步环境中有许多同时的请求,最终可能会阻塞所有的线程,请求将得不到响应。