2013-02-25 107 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