CsvHelper 并并行查询大型 csv 文件

CsvHelper and querying a large csv file in parallel

我有一个 3.6 gig 的 csv 文件。我正在使用 CsvHelper 来处理它。当我使用 linq 查询它时,它需要几分钟,我看到 CPU 在我的 PC 上最多只能显示大约 25%。执行此操作时,Linq 似乎可以很好地处理内存,因为它根本不会增加太多。

所以我想通过添加 .AsParallel() 我应该会看到一些性能提升。当我 运行 它时,我看到我的 CPU 上升到大约 95%,但它需要同样长的时间。

为什么我看不到 .AsParallel() 的性能提升,有什么方法可以通过它获得更好的性能(将其保留为 csv)。

string path = @"C:\my_3_gig_file.csv";

using (var csv = new CsvHelper.CsvReader(new StreamReader(path, Encoding.Default)))
{
                csv.Configuration.Delimiter = ",";
                csv.Configuration.TrimFields = true;
                var records = csv.GetRecords<MyClass>();

                var q1 = (from a in records.AsParallel()
                          where a.MY_HOUR == "1"
                          && a.MY_DATE == "14-JUN-13"
                          select a).ToList();
}

尝试并行处理行不会有任何收获,因此尝试没有意义。您只能使用 CsvHelper 线性读取和处理文件。即便如此,也没有足够的工作来证明行的并行处理是合理的。可能伤害你的是建立每一个被读取的记录。如果有很多列,那么每行的处理量就会很大。

您正在尝试从文件中过滤出要使用的行。您应该直接读入行,检查列,然后边做边建立记录。这样,您就不会浪费大量时间为每一行构建记录,而只是可能将其丢弃。

这是您可以执行此操作的一种方法。

List<T> GetCsvRecordsFiltered<T>(string path, Func<CsvReader, bool> filter, Action<CsvConfiguration> configure = null) where T : class
{
    using (var file = File.OpenText(path))
    using (var reader = new CsvReader(file))
    {
        configure?.Invoke(reader.Configuration);
        var result = new List<T>();
        while (reader.Read())
            if (filter(reader))
                result.Add(reader.GetRecord<T>());
        return result;
    }
}

然后当你读取文件时,你会这样做:

var q1 = GetCsvRecordsFiltered<MyClass>(path,
    reader => reader["MY_HOUR"] == "1" && reader["MY_DATE"] == "14-JUN-13",
    config => config.TrimFields = true
);

使用 AsParallel() 你不会看到任何性能提升,因为没有什么可以并行完成的。

之所以csv.GetRecords<MyClass>()returns是因为它yields记录。除非需要,否则它实际上不会读取任何文件。读取的每条记录只会从文件中读取一条记录(实际上是数据缓冲区)。

当您使用 linq 时,它必须读取整个 3.6 GB 的文件并对其进行解析以获得结果。您不可能执行 where 子句而不让它读取整个文件。当有其他 linq 提供程序时不会发生的原因,比如 sql,是因为建立了索引,并且 sql 只能提取它需要的记录。