如何让每个线程选择不同的项目?

时间:2015-12-22 11:28:40

标签: c# multithreading

我有一个有多个线程的程序。用户可以选择要选择的线程数量,并按此处理:

 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是每个线程在关闭之前必须完成的方法。 我有一个arraylist,它由多个项目(行)组成。

实施例

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

我真的希望你们中的一些先进的人可以帮助我解决这个问题,我不是那么先进:)

3 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

我强烈建议使用自4.0以来已包含在.NET中的Task-Parallel-Library(TPL)。任务不是完全线程,它们有效地抽象线程池。

这很好地解释了与TPL的细微差别:Multithreading or task parallel library

&'s

如果您需要传达进度,另一个有用的构造是IProgress,它代表了一个标准合同,用于根据需要将结果推送回UI。

&amp;'s

如果您需要更多流媒体,您可能需要查看TPL数据流。 (nuget包Microsoft.TPL.DataFlow)。

    [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

答案 2 :(得分:0)

除了Jakub Lortz的回答,如果你想创建自己的线程并使用更低级别的解决方案:

最简单的解决方案是拥有一个共享索引变量,并仅在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的答案更好,更清洁,如果它适合你。