【问题标题】:C# - Parallelizing While Loop with StreamReader causing High CPUC# - 使用 StreamReader 并行化 While 循环导致高 CPU
【发布时间】:2018-08-19 09:57:13
【问题描述】:
SemaphoreSlim sm = new SemaphoreSlim(10);

using (FileStream fileStream = File.OpenRead("..."))
using (StreamReader streamReader = new StreamReader(fileStream, Encoding.UTF8, true, 4096))
{
    String line;
    while ((line = streamReader.ReadLine()) != null)
    {
        sm.Wait();
        new Thread(() =>
        {
            doSomething(line);
            sm.Release();
        }).Start();
    }
}
MessageBox.Show("This should only show once doSomething() has done its LAST line.");

所以,我有一个非常大的文件,我想在每一行上执行代码。

我想并行执行,但一次最多 10 个。

我的解决方案是使用 SemaphoreSlim 在线程完成时等待并释放。 (由于函数是同步的,所以 .Release() 的放置是有效的)。

问题是代码占用大量 CPU。内存按预期运行,而不是加载超过 400mb,它只是每隔几秒就上下几mb。

但是 CPU 会发疯,它大部分时间都锁定在 100% 上长达 30 秒,然后稍微下降并返回。

由于我不想将每一行都加载到内存中,并且想要运行代码,所以这里最好的解决方案是什么?

在 9,700 行文件中输入 500 行。

270 万行文件中的 600 行输入。

编辑

按照 cmets 中的说明,我从 new Thread(()=>{}).Start(); 更改为 Task.Factory.StartNew(()=>{});,似乎是线程创建和销毁导致性能下降。这似乎是对的。在我移至 Task.Factory.StartNew 后,它的运行速度与信号量提到的相同,它的 CPU 与我的 Parallel.ForEach 代码版本完全相同。

【问题讨论】:

  • 这是因为您每次都创建和销毁线程...这会导致巨大的性能损失。
  • @Essigwurst 这不是 Parallel.ForEach 所做的吗?

标签: c# while-loop semaphore filestream streamreader


【解决方案1】:

您的代码创建了大量线程,效率低下。 C# 有更简单的方法来处理您的场景。一种方法是:

File.ReadLines(path, Encoding.UTF8)
    .AsParallel().WithDegreeOfParallelism(10)
    .ForAll(doSomething);

【讨论】:

  • 这不是一次加载每一行吗?我逐行这样做的原因是我的文件太大而无法将它们存储在内存中。
  • @user8549339 - 我添加了描述和文档。不,File.ReadLines 专为您的用例而设计,并根据需要懒惰地读取行。 ReadAllLines 会热切地阅读所有行。
  • s/while/whole
  • 哇,完美,它完全按照需要工作。我确实找到了线程问题的解决方案并将其添加到编辑中,但这将被标记为答案,因为它是我正在做的更方便的方式(只要你不介意 Linq)。
  • 完美!正是需要的。我原以为这会导致它实际加载内存中的每一行,但我猜不是。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-24
相关资源
最近更新 更多