长跑拦网方法.阻塞、睡眠、开始/结束和异步之间的区别
本文关键字:结束 异步 之间 区别 睡眠 方法 阻塞 开始 | 更新日期: 2023-09-27 18:01:00
这个问题与设计或模式以及使用哪个无关。这个问题的核心是关于线程和阻塞的情况。
本示例适用于任何旨在连续执行相同操作的阻塞方法。在这种情况下,它是对网络流的阻塞读取或写入。在线程和性能方面,这些方法在幕后是否有明显的差异?
我的假设是,下面的每个方法都会创建一个线程或使用一个池线程。然后阻塞该线程,直到有数据要读取。话虽如此,在这种情况下,这些方法在线程、性能和可伸缩性方面是否有明显的差异?
目前我正在创建一个服务器应用程序。该应用程序将有1000个客户端创建tcp连接。这些连接将保持打开状态,经常发送和接收少量数据。我希望使用模型A,因为它是最容易实现和最可维护的。无论选择哪种模式,我最终都会有1000个线程吗?
请注意,这些方法只是提供结构的概念,而不是在没有适当的流读取、超时和异常处理的情况下使用的方法。
方法A:阻断
Task.Factory.StartNew(ReadMessage,TaskCreationOptions.LongRunning);
private void ReadMessage()
{
while(true)
{
TcpClient.Read();
}
}
方法B:睡眠
Task.Factory.StartNew(ReadMessage,TaskCreationOptions.LongRunning);
private void ReadMessage()
{
while(true)
{
if(TcpClient.DataAvailable)
TcpClient.Read();
else
Thread.Sleep(1);
}
}
方法C:递归开始/结束
private void ReadMessage()
{
stream.BeginRead(readCallBack)
}
private void readCallBack()
{
stream.EndRead();
stream.BeginRead(readCallBack)
}
方法D:从BCL套接字异步。ReceiveAsync((
private void readCallBack()
{
while(true)
{
await socket.ReceiveAsync(eventArgs);
}
}
方法E:具有阻塞读取的异步方法(使用方法D进行调用,但它是一个自定义方法,而不是使用BCL中内置的套接字扩展(
private async Task<byte[]> ReceiveAsync()
{
return await Task.Factory.StartNew(() => TcpClient.Read());
}
我的假设是,下面的每个方法都会创建一个线程或使用一个池线程。然后阻塞该线程,直到有数据要读取。
一点也不。前两个示例阻塞线程,但后两个示例是异步的。
异步方法的工作方式是将工作排队到操作系统,然后等待回调,在这种情况下是在I/O完成端口上。因此,当读取挂起时,没有线程被使用。
由于异步方法不使用那么多线程,因此它们的扩展性更好。
您的最后一个示例(async
(实际上和您的第一个示例一样简单,除非您使用Rx或TPL Dataflow,否则这将是我建议的方法。在进行套接字通信时,当您考虑错误处理(如检测断开的连接(时,异步通信显然是可行的。