2013-02-25 65 views
3

此问题与设计或模式以及要使用的不相关。这个问题的核心是关于线程和阻塞的情况。长时间阻塞方法。阻塞,睡眠,开始/结束和异步之间的区别

本示例适用于任何旨在连续执行相同操作的阻止方法。在这种情况下,它是在网络流上阻塞读取或写入。在这些方法之间的线程和性能背后有什么明显的区别吗?

我的假设是,下面的每个方法创建一个线程或使用池线程。然后阻塞该线程直到有数据被读取。话虽如此,在这种情况下,这些方法之间的线程化,性能和可伸缩性是否有明显的区别?

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

private void readCallBack() 
{ 
    while(true) 
    { 
     await socket.ReceiveAsync(eventArgs); 
    } 
} 

方法E:异步方法与阻塞读(使用方法d打电话,但一个自定义的方法,而不是使用内置的从BCL插座exstendion)

private async Task<byte[]> ReceiveAsync() 
{ 
    return await Task.Factory.StartNew(() => TcpClient.Read()); 
} 

回答

1

我的假设是,每下面的方法创建一个线程或使用一个池线程。然后阻塞该线程直到有数据被读取。

根本不是。你的前两个例子阻塞线程,但你的后两个例子是异步的。

异步方法通过将工作排队到OS然后等待回调(在本例中为I/O完成端口)来工作。所以,当读取挂起时,没有线程被使用。

由于异步方法不使用尽可能多的线程,它们可以更好地扩展。

最后一个例子(async)与第一个例子一样简单,除非使用Rx或TPL Dataflow,否则这将是我推荐的方法。在进行套接字通信时,在您考虑错误处理(例如检测到丢失的连接)时,异步通信显然是您的选择。

+0

谢谢你的解释。它确实有帮助。我的最后一个问题是,方法D和新方法E有什么不同?方法E会不会阻塞线程和使用IOCP呢? – 2013-02-25 22:01:27

+1

“异步”方法中的阻塞I/O调用从来就不是一个好主意。方法E会阻塞调用线程而不使用IOCP。方法C和D使用IOCP并且不阻塞调用线程。 – 2013-02-26 00:34:41

+0

根据您的建议修正方法E.我想,答案仍然是,它会阻止一个线程,而不是使用IOCP – 2013-02-26 04:26:08