首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Parallel.For循环冻结

Parallel.For循环冻结
EN

Stack Overflow用户
提问于 2012-08-09 20:53:43
回答 2查看 1.2K关注 0票数 4

我试图并行地向DataTable添加一些信息,但是如果循环太长,它就会冻结,或者只是需要很多时间,比通常的for循环更多的时间,这是我在Parallel.For循环中的代码:

代码语言:javascript
复制
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循环比正常的循环花费更多的时间,有什么问题吗?

谢谢!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-08-09 21:03:00

你不能从两个不同的线程中改变一个DataTable;它的错误。DataTable不会尝试成为线程安全的。所以:不要那样做。只需从一个线程执行此操作即可。你很可能会受到IO的限制,所以你应该只在单个线程上作为一个流来做。看起来您正在处理文本数据。你似乎有一个线条的string[],也许是File.ReadAllLines()?好吧,这在这里是非常糟糕的:

  1. it强制将所有内容加载到内存中您必须等待所有内容加载到内存中
  2. CSV是多行格式;不能保证1行== 1行

您应该做的是使用类似于代码项目中的CsvReader,但即使您希望一次只使用一行,也可以使用StreamReader:

代码语言:javascript
复制
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!

票数 5
EN

Stack Overflow用户

发布于 2012-08-09 21:01:04

代码语言:javascript
复制
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);
  }
});
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11883897

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档