2015-12-22 18 views
2

我有一個程序有多個線程。用戶可以選擇將被選擇的線程的量和被作爲這樣的處理:如何讓每個線程選擇不同的項目?

for (int i = 0; i <= form.Bots - 1; i++) 
     { 
      (new Thread(() => { 

       doThreadWork(); 

       form.Console = "Thread(" + Thread.CurrentThread.ManagedThreadId + ") FINISHED " + usedCombos.Count + "/" + form.Combolist.Count; 




      })).Start(); 
     } 

doThreadWork是每個線程有關閉之前完成的方法。 我有一個數組列表,它由多個項目(行)組成。

Ex。

value:value 
value1:value1 
value2:value2 
value11:value11 
value4:value4 
value13:value13 

現在線程存在我的程序中,使處理這些值的過程更快。該程序檢查哪些值是有效的,哪些不是。 目前我已經實現了一個(可怕的?)方法來選擇要檢查的線程值。

int index = GetRandomNumber(0, form.Combolist.Count); 

得到一個隨機索引在列表中選擇。 我實現了這一點,因爲否則如果我只是使用foreach循環,每個線程將同時檢查相同的值。我需要得到像這樣的東西:

想象一下下面的控制檯日誌。每個線程都在同一時間運行。 價值觀總數是12線程運行的是4

Thread 1: checking index 1 
Thread 2: checking index 2 
Thread 3: checking index 3 
Thread 4: checking index 4 
Thread 1: checking index 5 
Thread 2: checking index 6 
Thread 3: checking index 7 
Thread 4: checking index 8 
Thread 1: checking index 9 
Thread 2: checking index 10 
Thread 3: checking index 11 
Thread 4: checking index 12 
Thread 1: FINISHED 
Thread 2: FINISHED 
Thread 3: FINISHED 
Thread 4: FINISHED 

我真的希望你們中的一些先進人物可以幫助我這個問題,我沒有那麼先進的:)

回答

4

C#提供了許多更高級別的方式來執行並行處理比產生新線程。您可以使用

一種選擇是parallel LINQ

int dop = 4;// set the number of threads to use 
form.Combolist 
    .AsParallel() 
    .WithDegreeOfParallelism(dop) 
    .ForAll(i => processElement(i)); 

你也可以使用Parallel.ForEach

+0

謝謝,這是一個簡單的解決方案,完成了這項工作。 –

0

除了LORTZ的Jakub的答案,如果你想創建自己的線程,並使用較低級別的解決方案:

最簡單的解決方案是有一個共同的指標變量,只改變其下lock

//global 
private readonly object indexLock = new object(); 
private int index; 
private ArrayList<WorkUnit> workUnits... 
//inside doThreadWork 
... 
lock(indexLock) 
{ 
    if(index > workUnits.Length) return; 
    WorkUnit work = WorkUnits[index]; 
    index += 1; 
} 
... 

稍高級別的解決方案是使用BlockingCollection。這是取代ArrayList有一個阻塞收集和每個線程只是Take'工作單位'反過來。

所有這些說Jakub Lortz回答更好,更清潔,如果它適合你。

1

我強烈推薦使用自.NET 4.0起包含在.NET中的任務並行庫(TPL)。任務不是正好是線程,它們有效地抽象了線程池。

這對解釋與TPL有關的細微差異做了很好的工作:Multithreading or task parallel library

[TestMethod] 
    public void ProcessBots() 
    { 
     string[] bots = new string[] { "A", "B", "C", "D", "E", "F", "G" }; 
     Parallel.ForEach(bots, bot => //use if you just want to foreach 
     { 
      this.TestContext.WriteLine(bot); 
     }); 
     Parallel.For(0, bots.Length, i => //use if you care about the index 
     { 
      this.TestContext.WriteLine(i.ToString()); 
     }); 
    } 

Test Name: ProcessBots 
Test Outcome: Passed 
Result StandardOutput: 
TestContext Messages: 
A 
D 
E 
F 
G 
B 
C 
0 
2 
3 
4 
5 
1 
6 

,如果你需要溝通進展IProgress另一個有用的結構,它代表了推結果反饋給你的用戶界面上的需求標準合同。

[TestMethod] 
    public void ProcessBots() 
    { 
     string[] bots = new string[] { "A", "B", "C", "D", "E", "F", "G" }; 
     IProgress<string> progress = new Progress<string>(str => 
     { 
      this.TestContext.WriteLine(str); 
     }); 
     Parallel.ForEach(bots, bot => 
     { 
      progress.Report(bot); 
     }); 
     Parallel.For(0, bots.Length, i => 
     { 
      progress.Report(i.ToString()); 
     }); 
    } 

如果您需要更多流式傳輸,您可能需要查看TPL數據流。 (nuget包Microsoft.TPL.DataFlow)。

[TestMethod] 
    public async Task ProcessBots() 
    { 
     string[] bots = new string[] { "A", "B", "C", "D", "E", "F", "G" }; 
     BroadcastBlock<string> getBotsBlock = new BroadcastBlock<string>(bot => bot, new ExecutionDataflowBlockOptions() { MaxDegreeOfParallelism = ExecutionDataflowBlockOptions.Unbounded }); 
     Random rand = new Random(); 
     ActionBlock<string> processBotsBlock = new ActionBlock<string>(async bot => 
     { 
      await Task.Delay(rand.Next(100, 1000)); 
      TestContext.WriteLine(bot); 
     }, new ExecutionDataflowBlockOptions() { MaxDegreeOfParallelism = ExecutionDataflowBlockOptions.Unbounded }); 
     ActionBlock<string> processBotsToLowerBlock = new ActionBlock<string>(async bot => 
     { 
      await Task.Delay(rand.Next(100, 1000)); 
      TestContext.WriteLine(bot.ToLower()); 
     }, new ExecutionDataflowBlockOptions() { MaxDegreeOfParallelism = ExecutionDataflowBlockOptions.Unbounded }); 
     getBotsBlock.LinkTo(processBotsBlock, new DataflowLinkOptions(){PropagateCompletion = true}); 
     getBotsBlock.LinkTo(processBotsToLowerBlock, new DataflowLinkOptions() { PropagateCompletion = true }); 
     foreach (var bot in bots) //note there is no parallelization here, you can post these on demand from any thread completely safe, where as the other solutions if the IEnumerable changes from another thread you have the potential for exceptions 
      getBotsBlock.Post(bot); 
     getBotsBlock.Complete(); 
     await processBotsBlock.Completion; 
     await processBotsToLowerBlock.Completion; 
    } 
Test Name: ProcessBots 
Test Outcome: Passed 
Result StandardOutput: 
TestContext Messages: 
c 
A 
G 
B 
f 
b 
e 
F 
C 
a 
d 
g 
E 
D 
相關問題