1

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

2 回答 2

3

尝试并行处理行不会获得任何收益,因此尝试没有意义。您只能使用 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
);
于 2016-03-10T21:07:52.800 回答
2

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

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

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

于 2016-03-10T21:43:23.350 回答