【问题标题】:Faster data checking and updating inside foreach loop在 foreach 循环中更快地检查和更新数据
【发布时间】:2017-12-29 18:21:07
【问题描述】:

我在下面的 while 语句中逐行从 StreamReader 读取数据。

while (!sr.EndOfStream)
{
   string[] rows = sr.ReadLine().Split(sep);

   int incr = 0;
   foreach (var item in rows)
   {
       if (item == "NA" | item == "" | item == "NULL" | string.IsNullOrEmpty(item) | string.IsNullOrWhiteSpace(item))
       {
           rows[incr] = null;
       }
       ++incr;
   }
    // another logic ...
}

代码运行良好,但由于 csv 文件很大(500,000,000 行和数百列),所以速度很慢。有没有更快的方法来检查数据(如果它是“NA”,“”,......应该用null代替)。目前我正在使用带有 incr 变量的 foreach 来更新 foreach 中的项目。

我想知道 linq 或 lambda 会更快,但我是这些领域的新手。

【问题讨论】:

  • linq 不太可能更快。您可以做的一件小事是摆脱 'item == ""' 检查,因为您已经有了 string.IsNullOrEmpty(item),还有 | IsNullOrEmpty 和 IsNullOrWhitespace 检查之间不会短路更改为 ||。
  • 我建议您将数据从 CSV 保存到数据库(根据情况使用关系或 NoSQL),然后使用它。会很快的。
  • 什么是// another logic?循环(for 是比foreach 更好的选择)应该很快
  • 另一个逻辑是SqlBulkCopy部分。但这不是本次任务的目标。
  • 您对程序进行了概要分析吗?标题提到了循环内的数据检查,但我认为与从文件中读取并拆分为列(你称之为行)的时间相比,进行检查和更新的时间是微不足道的

标签: c# linq


【解决方案1】:

首先,更改集合时不要使用foreach,这不是一个好习惯,尤其是当你已经使用了计数器变量时。

这个循环可以使用Parallel.For这样多线程:

使用正常的代码:

while (!sr.EndOfStream)
{
    string[] rows = sr.ReadLine().Split(sep);

    for (int i = 0; i < rows.Length; i++)
    {
        //I simplified your checks, this is safer and simplier.
        if (string.IsNullOrWhiteSpace(rows[i]) || rows[i] == "NA" || rows[i] == "NULL")
        {
            rows[i] = null;
        }
    }
    // another logic ...
}

代码使用Parallel.For

while (!sr.EndOfStream)
{
    string[] rows = sr.ReadLine().Split(sep);

    Parallel.For(0, rows.Length, i =>
    {
        if (string.IsNullOrWhiteSpace(rows[i]) || rows[i] == "NA" || rows[i] == "NULL")
        {
            rows[i] = null;
        }
    });
    // another logic ...
}

编辑

我们可以从另一个方面解决这个问题,但我不建议这样做,因为这需要 LOT 的 RAM,因为它必须将整个文件读入内存。

string[] lines = File.ReadAllLines("test.txt");
Parallel.For(0, lines.Length, x =>
{
    string[] rows = lines[x].Split(sep);

    for (int i = 0; i < rows.Length; i++)
    {
        if (string.IsNullOrWhiteSpace(rows[i]) || rows[i] == "NA" || rows[i] == "NULL")
        {
            rows[i] = null;
        }
    }
});

但我不认为这是值得的。你决定。这些类型的操作不能很好地与并行化配合使用,因为它们的计算时间太短,开销太大。

【讨论】:

  • 如果性能真的很重要,别忘了限制Parallel For msdn.microsoft.com/en-us/library/…的线程数
  • 我尝试了正常循环、并行循环和我原来的 foreach 方法。 Foreach 和普通循环几乎相同,但最慢的是惊人的并行循环。
  • @mateskabe 你在发布模式下检查了吗?
  • 是的,我只在发布模式下测试这些方法
  • 是的,我也会尝试使用批量复制方法。非常感谢您的宝贵时间!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-10
  • 1970-01-01
  • 2015-04-28
  • 2018-12-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多