CsvHelper并行查询大型csv文件

时间:2016-03-10 18:55:53

标签: c# linq csvhelper

我有一个3.6 gig的csv文件。我正在使用CsvHelper来处理它。当我使用linq查询它时,它需要几分钟,我看到CPU在我的电脑上最大只有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();
}

2 个答案:

答案 0 :(得分:1)

通过尝试并行处理行,你将无法获得任何东西,所以没有必要尝试。您只能使用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
);

答案 1 :(得分:1)

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

csv.GetRecords<MyClass>()立即返回的原因是因为它yields会记录。在需要之前,它实际上不会读取任何文件。每个读取的记录只读取文件中的一条记录(实际上是数据缓冲区)。

当你使用linq时,它必须读取整个3.6 GB文件并解析它以获得结果。您无法执行where子句并且无法读取整个文件。当有其他linq提供程序(如sql)时,没有发生的原因是因为构建了索引,并且sql只能提取它所需的记录。