2013-03-03 31 views
7

好的在這裏我的問題。我想開始線程,直到一定數量。讓我們說100.所以它將開始啓動線程並連續檢查正在運行的線程的數量。 當達到最大數量時,它將停止開始新線程。但有了適當的檢查間隔或完成的線程會發出信號,它會啓動新的線程。如何使一定數量的線程始終運行

用這種方法,我總是會有一定數量的正在運行的線程。

我管理這與睡眠和永久。所以我不斷檢查總運行線程數與給定的時間間隔,如果線程完成,處置它,並開始一個新的。

但我的解決方案並不是以正確的方式來到我身邊。我想如果完成的線程會發出信號,並且如果我們低於最大線程數閾值,檢查器將開始一個新的線程會更好。

我看到了很多線程池的例子,但其中大多數不包含任何排隊池和最大數量的正在運行的線程。我的意思是,他們只是開始線程,直到他們完成。但讓我們說,我有500k的收穫。我不能只是在帶有線程池的for循環中啓動它們。

平臺是c#4.5 WPF應用程序

下面是我的解決方案。其實我正在尋找一個更好的。沒有改善這一個。

private void Button_Click_4(object sender, RoutedEventArgs e) 
{ 
    Task.Factory.StartNew(() => 
    { 
     startCrawler(); 
    }); 
} 

void startCrawler() 
{ 
    int irMaximumThreadcount = 100; 
    List<Task> lstStartedThreads = new List<Task>(); 
    while (true) 
    { 
     for (int i = 0; i < lstStartedThreads.Count; i++) 
     { 
      if (lstStartedThreads[i].IsCompleted == true) 
      { 
       lstStartedThreads[i].Dispose(); 
       lstStartedThreads.RemoveAt(i); 
      } 
     } 

     if (lstStartedThreads.Count < irMaximumThreadcount) 
     { 
      var vrTask = Task.Factory.StartNew(() => 
      { 
       func_myTask(); 
      }); 
      lstStartedThreads.Add(vrTask); 
     } 

     System.Threading.Thread.Sleep(50); 
    } 
} 

void func_myTask() 
{ 

} 
+0

「我不能只是在帶有線程池的for循環中啓動它們。」 - 你真的嘗試過嗎?假設它會使您的整體互聯網連接速度更快,開始多線程聽起來並不「合適」。另外Conisder使用異步操作 - 不需要那麼多的線程......除非你有類似32核心的機器...... – 2013-03-03 03:44:15

回答

6

我個人使用PLINQ對於這一點,並且特別是WithDegreeOfParallelism方法這限制併發執行,以值傳遞的數量。

private IEnumerable<Action> InfiniteFunctions() 
{ 
    while(true) 
    { 
     yield return func_myTask; 
    } 
} 

private void Button_Click_4(object sender, RoutedEventArgs e) 
{ 
    int irMaximumThreadcount = 100; 
    InfiniteFunctions() 
     .AsParallel() 
     .WithDegreeOfParallelism(irMaximumThreadcount) 
     .ForAll(f => f()); 
} 

編輯:實際上閱讀文檔似乎irMaximumThreadCount只能是最大值爲64,所以要注意這一點。

編輯2:好了,有一個更好的外觀和它似乎Parallel.ForEach需要ParallelOptions參數,包括MaxDegreeOfParallelism屬性,不限 - Check it out。所以你的代碼可能是這樣的:

private void CrawlWebsite(string url) 
{ 
    //Implementation here 
} 

private void Button_Click_4(object sender, RoutedEventArgs e) 
{ 
    var options = new ParallelOptions() 
    { 
     MaxDegreeOfParallelism = 2000 
    }; 

    Parallel.ForEach(massiveListOfUrls, options, CrawlWebsite); 
} 
+0

現在這很有趣。所以你說這個方法可以用於抓取500k頁面。讓我試試:) – MonsterMMORPG 2013-03-03 02:23:05

+0

哦。那麼它對我來說是沒用的:)我開始2000線程來檢查活動代理,例如^^,即使任務管理器顯示490個線程。我不知道爲什麼不是2000 :) – MonsterMMORPG 2013-03-03 02:26:39

+0

啊,小心我的編輯 - 最大隻有64並行。是的,你可以遍歷500,000項目的清單並執行每個項目的func。 – Felix 2013-03-03 02:27:40

0

不是一個確切的答案,但我認爲這可能引導你在正確的方向。

首先,看看Thread.Join,特別是在本頁底部給出的簡單示例。這種方法優於Thread.Sleep(),更適合你的目的。我正在考慮* 行加入 *在「管理器」線程而不是* 睡眠 * ing。

第二個選項可能會或可能不適合您的目的,是新的Tasks庫。由於您使用的是最新版本的框架,因此此選項可用,但是我想您無法控制任務庫創建的實際線程數。它會根據底層調度程序自動選擇該值。但是,有一個名爲ParallelOptions.MaxDegreeOfParallelism的選項聽起來很有趣。

+0

。我錯了嗎?如果是這樣,我該如何使用它?我不需要等待所有任務。當一個任務完成後,另一個將立即啓動,所以總會有一定數量的任務運行 – MonsterMMORPG 2013-03-03 02:21:55

+0

mmmm ...不是100%確定的,但我認爲Join只停止調用線程。另一個想法可能是加入新創建的工作線程,以便當其中一個當前正在運行的線程表示它已完成時立即開始工作,因此經理不必一遍又一遍地檢查。 – dotNET 2013-03-03 02:28:04

+0

不行,不行。因爲線程是獨立完成的。首先開始可能會完成最後或最後開始可能會先完成。 – MonsterMMORPG 2013-03-03 02:31:45

1

.NET 4.0引入了幾個具有內置併發管理的集合,這對於這種情況應該很理想。一個阻塞集合會更有效,然後在一個while循環中休眠。然後您只產生從阻塞隊列中讀取的x個線程。

BlockingCollection<string> queue = new BlockingCollection<string>(listOfUrls); 

for (int x=0; x < MaxThreads; x++) 
{ 
    Task.Factory.StartNew(() => 
    { 
     while (true) 
     { 
      string url = queue.Take(); // blocks until url is available 
      // process url; 
     } 
    }, TaskCreationOptions.LongRunning); 
} 

您將任務標記爲長時間運行,因此它將創建它自己的線程而不是使用線程池。如果您需要先進先出,則可以將ConcurrentQueue<T>傳遞給阻塞集合構造函數。 http://msdn.microsoft.com/en-us/library/dd287085.aspx

3

您正在將任務與線程混合在一起。任務不是一個線程。 There is no guarantee that each task will have it's own thread

其實TPL(Task Parallel Library)是某種隊列。這意味着您可以爲每個FuncAction對象創建並啓動任務。 There is no easy way to control the number of threads實際上已創建。

但是,您可以創建很多任務,而且開銷很小,因爲TPL會將它們排入隊列並應用更多邏輯來平衡thread pool的線程上的工作。

如果需要依次執行某些任務,則可以使用Task.ContinueWith排列它們。也可以使用Task.Factory.ContinueWhenAnyTask.Factory.ContinueWhenAll開始新任務。

這也是您如何控制要創建的並行任務數量的線索:只需創建所需數量的任務並使用ContinueWhenAny排隊其餘任務即可。每次任務結束時,下一個將開始。

再次說明:TPL將平衡線程池中線程間的工作。無論如何你需要考慮的是使用其他資源,如磁盤I/O或互聯網連接。嘗試同時使用相同資源的許多任務可能會大大減慢程序的運行速度。

+0

我有很多資源。每秒850 MB I/O讀寫速度,50 mbit光纖連接。無論如何,這是一些有用的信息投票:) – MonsterMMORPG 2013-03-03 11:53:21