【发布时间】:2020-12-08 17:40:54
【问题描述】:
我有一段 C# 代码如下。这段代码总结了 DataTable 中的一列“双打”:
var data = this.Db.ExecuteRead(query, this.Score.Name);
var time = 0.0;
foreach (DataRow row in data.Rows)
{
time += this.ParseDouble(row[0].ToString()) / MillisecondsPerMinute;
}
此代码需要 4 秒才能执行。我想加快速度,所以我将其并行化如下:
Parallel.ForEach(
data.AsEnumerable(),
row =>
{
time += this.ParseDouble(row[0].ToString()) / MillisecondsPerMinute;
});
此代码需要 3 秒才能执行。它也会导致碰撞。我不认为“双”线程是安全的。这是意料之中的。然后我添加了一个 Mutex 以使其线程安全:
Parallel.ForEach(
data.AsEnumerable(),
row =>
{
mut.WaitOne();
ptime += this.ParseDouble(row[0].ToString()) / MillisecondsPerMinute;
mut.ReleaseMutex();
});
这段代码要慢得多。执行需要 15 秒,但会产生准确的结果。我的问题是,我最好还是在这里使用标准的“ForEach”,还是可以以更好的方式实现多线程?
作为参考,这里是 ParseDouble 方法:
protected double ParseDouble(string text)
{
double value;
if (!double.TryParse(text, out value))
{
throw new DoubleExpectedException();
}
return value;
}
【问题讨论】:
-
并非所有问题都可以通过并行/并发解决方案更快地解决。这取决于占用最多时间的内容。首先检查
var data = Db.ExecuteRead(query, Score.Name).ToList();需要多长时间。如果这很慢,那么优化处理将解决不了多少问题。然后对于这样的事情,最好对问题进行分区,计算数据块的值。然后在你完成后合并所有的块结果(应该快速简单)。有一个Parallel.ForEach重载需要Partitioner来帮助解决这个问题。 -
您能否在问题中包含
ParseDouble方法?还有多少行有DataTable? -
“它也会导致冲突。” double time这个变量最后没有正确的值吗?
-
@TheodorZoulias 关于碰撞:当我不使用 Mutex 时,
double time总是不同的,并且总是低于应有的值。 -
@TheodorZoulias 我已将 ParseDouble 方法添加到问题中。
标签: c# thread-safety parallel.foreach