C# 长时间运行的阻塞方法。阻塞、休眠、开始/结束和异步之间的区别

C# 长时间运行的阻塞方法。阻塞、休眠、开始/结束和异步之间的区别,c#,blocking,networkstream,thread-sleep,C#,Blocking,Networkstream,Thread Sleep,这个问题不是关于设计或模式以及使用哪一个。这个问题的核心是关于线程和阻塞的情况 此示例适用于设计为连续执行相同操作的任何阻塞方法。在这种情况下,它是对网络流的阻塞读取或写入。这些方法在线程和性能方面在幕后是否有明显的差异 我的假设是,下面的每个方法都创建一个线程或使用一个池线程。然后阻塞该线程,直到有数据要读取。话虽如此,在这种情况下,两种方法在线程、性能和可伸缩性方面是否存在明显的差异 目前我正在创建一个服务器应用程序。此应用程序将有1000个客户端创建tcp连接。这些连接将保持打开状态,经常

这个问题不是关于设计或模式以及使用哪一个。这个问题的核心是关于线程和阻塞的情况

此示例适用于设计为连续执行相同操作的任何阻塞方法。在这种情况下,它是对网络流的阻塞读取或写入。这些方法在线程和性能方面在幕后是否有明显的差异

我的假设是,下面的每个方法都创建一个线程或使用一个池线程。然后阻塞该线程,直到有数据要读取。话虽如此,在这种情况下,两种方法在线程、性能和可伸缩性方面是否存在明显的差异

目前我正在创建一个服务器应用程序。此应用程序将有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()

方法E:带阻塞读取的异步方法(使用方法D调用,但它是一个自定义方法,而不是使用BCL中内置的套接字exstendion)

private async Task ReceiveAsync()
{
返回wait Task.Factory.StartNew(()=>TcpClient.Read());
}
我的假设是,下面的每个方法都创建一个线程或使用一个池线程。然后阻塞该线程,直到有数据要读取

一点也不。前两个示例阻止线程,但后两个示例是异步的

异步方法的工作方式是将工作排队到操作系统,然后等待回调,在本例中是在I/O完成端口上。因此,当读取挂起时,没有线程被使用

由于异步方法不使用那么多线程,因此它们的扩展性更好


您的最后一个示例(
async
)实际上与您的第一个示例一样简单,这将是我推荐的方法,除非您使用Rx或TPL数据流。在进行套接字通信时,当您考虑错误处理(如检测连接丢失)时,异步通信显然是该走的路。

谢谢您的解释。这真的很有帮助。我的最后一个问题是,方法D和新方法E之间有区别吗?在不阻塞线程而使用IOCP的情况下,方法E的性能会一样好吗?在
async
方法中阻塞I/O调用从来都不是一个好主意。方法E将阻止调用线程,而不使用IOCP。方法C和D使用IOCP并且不阻塞调用线程。根据您的建议修复了方法E。我想答案仍然是它将阻塞线程而不使用IOCPRight。它阻塞线程池线程而不是调用线程,但它仍然阻塞线程。
private void readCallBack()
{
    while(true)
    {
        await socket.ReceiveAsync(eventArgs);
    }
}
private async Task<byte[]> ReceiveAsync()
{
   return await Task.Factory.StartNew(() => TcpClient.Read());
}