在foreach循环内更快地检查和更新数据

时间:2017-12-29 08:35:19

标签: c# linq

我在以下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会更快但我在这些方面都很新。

1 个答案:

答案 0 :(得分:5)

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

可以使用Parallel.For这种方式使这个循环成为多线程:

使用normal的代码:

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;
        }
    }
});

但我不认为这是值得的。你决定。这些类型的操作在并行化方面效果不佳,因为它们只需要很少的时间来计算,而且开销太大了。