2012-04-05 62 views
11

我正在編寫一個客戶端模擬程序,其中所有模擬的客戶端都運行一些針對服務器的預定義例程 - 這是一個運行在具有四個實例的azure中的Web服務器。我應該使用線程還是任務 - 多客戶端模擬

所有模擬的客戶端在連接到服務器後運行相同的例程。

在任何時候我都想使用我的程序來模擬300到800個客戶端。

我的問題是: 我應該創建客戶端類的N個實例並在N個不同的線程中運行它們嗎?或

我應該使用任務庫來做這件事嗎?

+0

[請參閱相關討論](http://stackoverflow.com/questions/10687850/task-factory-startnew-or-parallel-foreach-for-many-long-running-tasks) – 2012-10-20 15:48:43

回答

20

你當然不應該創建800個線程。

讓我們回到這裏。你有一個稱爲「服務器」的設備,它接收來自「客戶」的「請求」並將「響應」發回給這些客戶。假設這些請求是郵局發送的紙張,而回復是包含書本的郵箱,郵箱也是由郵局發送的。

您希望模擬爲了測試服務器的800個客戶端。

假設線程是人,處理器是椅子。一個人只能坐在椅子上工作。

創建800個線程相當於外出和僱用800人,並支付他們每個人發送一封信到服務器。但你只有四把椅子,所以這800人必須輪流使用椅子。

這將是一個滑稽在現實生活中的解決方案。線程,像人一樣,瘋狂昂貴。您應該儘量減少您創建的線程數量。

那麼,您是否應該通過任務工廠創建800個任務,讓TPL將它們並行化爲您?

不,你不應該那樣做。 TPL有一羣人(線程)可以從中抽取,並且它試圖安排一些事情,以免工資單中的人比坐在椅子上的人多。但是你的任務不是「限制椅子」的 - - 人們將坐在椅子上,將請求發送到服務器,然後在等待響應回來時離開椅子。 當他們在等待時,TPL現在不得不僱用更多的人來處理額外的任務。

打開Web服務器是I/O綁定; 您應該只爲CPU綁定的任務創建線程池任務。

正確的解決辦法是聘請兩位人。

一個人 - 「I/O完成線程」 - 除了刪除郵箱中的請求並檢查傳入的包之外什麼都不做。另一個人 - 「模擬」人員 - 制定正確的「時間表」來模擬800個客戶。模擬人員制定時間表,然後進入睡眠狀態。當需要發送另一個請求到服務器時,她醒來。當她醒來時,她告訴I/O完成線程將這封信放在郵箱中,並在響應進入時將其喚醒。然後,她回到睡眠狀態,直到發送另一個請求或響應進來需要驗證。

您應該做的是(1)獲取C#5的beta版本並使用async/await創建向服務器發送請求的任務,然後將控制權交還給消息循環,直到要發送另一個消息請求或響應。​​或者,如果您不想使用C#5,則應創建一個任務完成源,並設置具有正確延續性的任務。

簡而言之:處理許多並行I/O任務的正確方法是創建非常少量的線程,每個線程一次只執行非常少量的工作。讓I/O完成線程處理I/O的細節。 您不需要僱用800人來模擬發送800封信件。聘請兩個人,一個看郵箱和一個寫信。

+2

如果它們很長運行與服務器的交互? – Tudor 2012-04-05 19:38:38

1

我會使用任務庫並讓任務庫爲您處理所有線程。你不想旋轉800個線程。在同一時間同時執行多個併發線程是一個糟糕的主意,下面是另一個堆棧溢出問題:Maximum number of threads in a .NET app?

2

在這種情況下的答案並不那麼簡單。這真的取決於你希望你的客戶進行模擬:

  1. 如果你想擁有800級連接的客戶端,但不一定在同一時間,它的使用Task個好主意。它們重量輕,可以有效利用潛在的ThreadPool

  2. 如果你真的希望客戶端完全平行,恐怕沒有辦法真正避免線程。沒有不可思議的方式來獲得800個輕量級的同時執行任務。 Task抽象是輕量級的,因爲它使用線程池。這意味着許多任務都映射到少量的實際線程。但是,當然,這意味着它們並不是真正並行運行,而是計劃在可能的情況下運行。 ThreadPool的最大線程數爲250(AFAIK),因此如果您使用Task s,實際上不會超過250個「客戶端」。該解決方案將最大線程設置爲800,但此時與使用經典線程相同。

1

對於此application domains是你最好的選擇。

安裝應用程序域是執行.NET應用程序的隔離的運行時單元。它提供了一個託管的內存邊界,一個用於應用程序配置設置的容器以及爲分佈式應用程序提供通信接口。

每個.NET應用程序通常只託管一個應用程序域,該應用程序域在給定進程/程序啓動時由CLR自動創建。在某個情況下,您可以通過單個進程/程序創建其他應用程序域。使用多個應用程序域可避免通信複雜性,並可使用多個單獨的進程並提供您的任務分離。

對於你想要的你有兩個選擇。

  1. 在同一個域中的單獨線程上啓動X個線程。

這將意味着你將有非常疲乏的是線程安全的,這將是非常困難的這樣一個任務,模擬多次登錄,模擬客戶等

  1. 啓動X線在同一個進程中,每個進程在它自己的應用程序域中

這將保持每個紡紗線程隔離,也容易訪問託管應用程序/程序。通過具有各位X模擬在X單獨的應用程序域,每個域將被分離,並無法通過靜態類成員等另一客戶端仿真干擾

通過提取從約瑟夫阿爾巴哈利的書C# 4.0 In a Nutshell輔助下,其我強烈建議得到:

的40個併發客戶端模擬一個例子可能是你有幫助:

class program 
{ 
    static void main() 
    { 
     // Create 40 domains and 40 threads. 
     AppDomain[] domains = new AppDomain[40]; 
     Thread[] thread = new Thread[40]; 

     for (int i = 0; i < 40; i++) 
     { 
      domains[i] = AppDomain.CreateDomain("Client Simulation " + i); 
      thread[i] = new Thread(SimulateClientInOtherDomain); 
     } 

     // Start all threads, passing to each thread its app domain. 
     for (int j = 0; j < 40; j++) 
      threads[j].Start(domains[j]); 

     // Wait for the threads to finish. 
     for (int k = 0; k < 40; k++) 
      threads[k].Join(); 

     // Unload the application domains. 
     for (int l = 0; l < 40; l++) 
      AppDomain.Unload(domains[l]); 
    } 

    // Thread start with input of with domain to run on/in. 
    static void SimulateClientInOtherDomain(object domain) 
    { 
     ((AppDomain)domain).DoCallBack(Simulate); 
    } 

    static void Simulate() 
    { 
     Client simClient1 = new Client("Bill", "Gates", ...); 
     simClient1.Simulate(); 
    } 
} 

我希望這有助於。

相關問題