我有一个有多个线程的程序。用户可以选择要选择的线程数量,并按此处理:
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
我真的希望你们中的一些先进的人可以帮助我解决这个问题,我不是那么先进:)
答案 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。
&'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的答案更好,更清洁,如果它适合你。