我有一个多行文本框,我想用多线程处理每一行。
文本框可能有很多行(1000+),但线程不多。我想使用自定义线程数来读取所有1000多行而没有任何重复(如在每个线程中只读取UNIQUE行,如果一行已被其他线程读取,则不再读取它)。
我现在拥有的:
private void button5_Click(object sender, EventArgs e)
{
for (int i = 0; i < threadCount; i++)
{
new Thread(new ThreadStart(threadJob)).Start();
}
}
private void threadJob()
{
for (int i = 0; i < txtSearchTerms.Lines.Length; i++)
{
lock (threadLock)
{
Console.WriteLine(txtSearchTerms.Lines[i]);
}
}
}
它确实启动了正确数量的线程,但它们都多次读取相同的变量。
答案 0 :(得分:3)
计算后分离数据收集和数据处理以及下一步可能的步骤。您可以使用ConcurrentBag<T>
安全地收集并行计算的结果,这只是线程安全的集合
那你就不用担心&#34;锁定&#34;对象和所有行将被处理&#34;只有一次。
1.收集数据
2.并行执行收集的数据
3.处理计算结果
private string Process(string line)
{
// Your logic for given line
}
private void Button_Click(object sender, EventArgs e)
{
var results = new ConcurrentBag<string>();
Parallel.ForEach(txtSearchTerms.Lines,
line =>
{
var result = Process(line);
results.Add(result);
});
foreach (var result in results)
{
Console.WriteLine(result);
}
}
默认情况下,Parallel.ForEach
将使用底层调度程序提供的线程数。
您可以通过将ParallelOptions
的实例传递给Parallel.ForEach
方法来控制已用线程的数量。
var options = new ParallelOptions
{
MaxDegreeOfParallelism = Environment.ProcessorCount
};
var results = new ConcurrentBag<string>();
Parallel.ForEach(values,
options,
value =>
{
var result = Process(value);
results.Add(result);
});
答案 1 :(得分:0)
考虑使用execve()
迭代fork
数组。 它就像一个普通的Parallel.ForEach
循环(即每个值只会处理一次),但工作是并行完成的 - 多个Lines
s(线程)。
foreach
以上代码需要在您的文件顶部添加此行:
Task
或者,如果您不仅要执行某些内容,还要 return / project ,那么请尝试:
var data = txtSearchTerms.Lines;
var threadCount = 4; // or whatever you want
Parallel.ForEach(data,
new ParallelOptions() { MaxDegreeOfParallelism = threadCount },
(val) =>
{
//Your code here
Console.WriteLine(val);
});
仍然并行执行代码,但也返回using System.Threading.Tasks;
(在这种情况下,原始var results = data.AsParallel(new ParallelLinqOptions()
{
MaxDegreeOfParallelism = threadCount
}).Select(val =>
{
// Your code here, I just return the value but you could return whatever you want
return val;
}).ToList();
中的值相同)。最重要的是, List
与您的输入的顺序相同。
答案 2 :(得分:-1)
有很多方法可以做到你想要的。
采取额外的课程字段:
private int _counter;
使用它而不是循环索引。在锁内增加它:
private void threadJob()
{
while (true)
{
lock (threadLock)
{
if (_counter >= txtSearchTerms.Lines.Length)
return;
Console.WriteLine(txtSearchTerms.Lines[_counter]);
_counter++;
}
}
}
它有效,但效率很低。
让我们考虑另一种方式。每个线程将独立于其他线程处理其数据集的一部分。
public void button5_Click(object sender, EventArgs e)
{
for (int i = 0; i < threadCount; i++)
{
new Thread(new ParameterizedThreadStart(threadJob)).Start(i);
}
}
private void threadJob(object o)
{
int threadNumber = (int)o;
int count = txtSearchTerms.Lines.Length / threadCount;
int start = threadNumber * count;
int end = threadNumber != threadCount - 1 ? start + count : txtSearchTerms.Lines.Length;
for (int i = start; i < end; i++)
{
Console.WriteLine(txtSearchTerms.Lines[i]);
}
}
这更有效,因为线程不会等待锁定。但是,数组元素的处理方式不一般。