我试图并行地向DataTable添加一些信息,但是如果循环太长,它就会冻结,或者只是需要很多时间,比通常的for循环更多的时间,这是我在Parallel.For循环中的代码:
Parallel.For(1, linii.Length, index =>
{
DataRow drRow = dtResult.NewRow();
alResult = CSVParser(linii[index], txtDelimiter, txtQualifier);
for (int i = 0; i < alResult.Count; i++)
{
drRow[i] = alResult[i];
}
dtResult.Rows.Add(drRow);
}
);怎么了?这个Parallel.For循环比正常的循环花费更多的时间,有什么问题吗?
谢谢!
发布于 2012-08-09 21:03:00
你不能从两个不同的线程中改变一个DataTable;它的将错误。DataTable不会尝试成为线程安全的。所以:不要那样做。只需从一个线程执行此操作即可。你很可能会受到IO的限制,所以你应该只在单个线程上作为一个流来做。看起来您正在处理文本数据。你似乎有一个线条的string[],也许是File.ReadAllLines()?好吧,这在这里是非常糟糕的:
您应该做的是使用类似于代码项目中的CsvReader,但即使您希望一次只使用一行,也可以使用StreamReader:
using(var file = File.OpenText(path)) {
string line;
while((line = file.ReadLine()) != null) {
// process this line
alResult = CSVParser(line, txtDelimiter, txtQualifier);
for (int i = 0; i < alResult.Count; i++)
{
drRow[i] = alResult[i];
}
dtResult.Rows.Add(drRow);
}
}这将不会更快使用Parallel,所以我没有尝试这样做。在这里,IO是您的瓶颈。锁定将是一种选择,但它不会对您有很大帮助。
顺便说一句,我注意到alResult没有在循环中声明。这意味着在您的原始代码中,alResult是一个捕获的变量,它在所有循环迭代之间共享-这意味着您已经可怕地覆盖了每一行。
编辑:说明为什么Parallel与从文件中读取1,000,000行无关:
方法1:使用ReadAllLines加载行,然后使用Parallel处理它们;这会占用物理文件IO的固定时间,然后使用和进行并行处理。CPU的工作量很小,我们基本上花了固定的时间。然而,我们增加了大量的线程开销和内存开销,而且在加载完所有文件之前,我们甚至不能启动。
方法2:使用流API;逐行读取每一行-处理每一行并添加它。这里的成本基本上又是:实际IO带宽加载文件的固定时间。但是,我们现在没有线程开销,没有同步冲突,没有巨大的内存可供分配,并且我们立即开始填充表。
方法3:如果你真的想要,第三种方法是一个读/写队列,一个专用的线程处理文件IO并将行排入队列,第二个线程执行DataTable。坦率地说,这是更多的移动部分,第二个线程将花费95%的时间等待来自文件的数据;坚持使用方法2!
发布于 2012-08-09 21:01:04
Parallel.For(1, linii.Length, index =>
{
alResult = CSVParser(linii[index], txtDelimiter, txtQualifier);
lock (dtResult)
{
DataRow drRow = dtResult.NewRow();
for (int i = 0; i < alResult.Count; i++)
{
drRow[i] = alResult[i];
}
dtResult.Rows.Add(drRow);
}
});https://stackoverflow.com/questions/11883897
复制相似问题