4

我正在尝试在 Parallel 中向 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 循环比正常循环花费更多的时间,有什么问题吗?

谢谢!

4

2 回答 2

5

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

  1. 它迫使它全部加载到内存中
  2. 你必须等待它全部加载到内存中
  3. CSV 是一种多行格式;不能保证 1 行 == 1 行

应该做的是使用代码项目中的 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 行无关:

方法一:使用ReadAllLines加载行,然后使用Parallel处理;这花费了物理文件 IO 的 [固定时间],然后我们进行并行化。CPU 工作量很小,我们基本上已经花费了[固定时间]。但是,我们增加了很多线程开销和内存开销,甚至在所有文件都加载完之后才能开始。

方法2:使用流式API;逐行读取每一行 - 处理每一行并添加它。这里的成本基本上又是:[固定时间]实际IO带宽加载文件。但; 我们现在没有线程开销,没有同步冲突,没有要分配的巨大内存,我们立即开始填表。

方法 3:如果您真的想要,第三种方法是读取器/写入器队列,一个专用线程处理文件 IO 并将行排入队列,第二个处理DataTable. 坦率地说,它有更多的活动部件,第二个线程将花费 95% 的时间等待来自文件的数据;坚持方法2!

于 2012-08-09T13:02:59.980 回答
1
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);
  }
});
于 2012-08-09T13:01:04.187 回答