C# 中的密集文件 I/O 和数据处理

Posted

技术标签:

【中文标题】C# 中的密集文件 I/O 和数据处理【英文标题】:Intensive file I/O and data processing in C# 【发布时间】:2010-01-20 21:41:50 【问题描述】:

我正在编写一个需要处理大型文本文件的应用程序(用逗号分隔的几种不同类型的记录 - 我没有权力或倾向于更改数据存储格式)。它读取记录(通常是按顺序读取文件中的所有记录,但并非总是如此),然后将每条记录的数据传递给某些处理。

现在这部分应用程序是单线程的(读取一条记录,处理它,读取下一条记录等)我认为在一个线程中读取队列中的记录并处理可能更有效它们在另一个线程中以小块的形式或可用时。

我不知道如何开始编写类似的程序,包括必要的数据结构或如何正确实现多线程。任何人都可以提供任何指示,或提供其他关于我如何提高性能的建议吗?

【问题讨论】:

在 CodeProject 和 Filehelpers.com 上查看这篇文章 here 你知道你大部分时间都花在了哪里,阅读还是处理?我假设后者。根据发生的情况,您可能希望考虑对其进行优化。例如,如果您处理对文件或数据库的写入,如果可以的话,最好分批进行。 这取决于...我会说 15% 到 40% 的时间都花在了处理上。不需要做很多处理。我当然会尝试进一步优化该阶段,但我知道这个应用程序将从多线程中受益。 【参考方案1】:

如果您能够平衡处理记录的时间与阅读记录的时间,您可能会受益;在这种情况下,您可以使用生产者/消费者设置,例如synchronized queue 和工作人员(或少数)出列和处理。我也可能想研究并行扩展;编写阅读代码的IEnumerable<T> 版本非常容易,之后Parallel.ForEach(或其他Parallel 方法之一)实际上应该做你想做的一切;例如:

static IEnumerable<Person> ReadPeople(string path) 
    using(var reader = File.OpenText(path)) 
        string line;
        while((line = reader.ReadLine()) != null) 
            string[] parts = line.Split(',');
            yield return new Person(parts[0], int.Parse(parts[1]);
        
    

【讨论】:

您的阻塞队列似乎正是我要找的,谢谢。我今天会试试。 无锁队列怎么样:boyet.com/Articles/LockfreeQueue.html?这对我来说会有所改善吗?如何使用分析器来确定等待其他线程的锁被释放所花费的时间?【参考方案2】:

看看这个教程,它包含了你所需要的一切......这些是微软教程,包括你描述的类似案例的代码示例。您的生产者填充队列,而消费者弹出记录。

Creating, starting, and interacting between threads

Synchronizing two threads: a producer and a consumer

【讨论】:

【参考方案3】:

您还可以查看异步 I/O。在这种风格中,您将从主线程开始文件操作,然后它将继续在后台运行,完成后,它会调用您指定的回调。同时,您可以继续做其他事情(例如处理数据)。例如,您可以启动一个异步操作来读取接下来的 1000 个字节,然后处理您已经拥有的 1000 个字节,然后等待下一个千字节。

不幸的是,用 C# 编写异步操作有点痛苦。有一个MSDN sample,但一点也不好看。这可以在 F# 中使用异步工作流很好地解决。我写了一篇文章来解释这个问题,并展示了如何使用C# iterators 做类似的事情。

一个更有前途的 C# 解决方案是 Wintellect PowerThreading 库,它支持使用 C# 迭代器的类似技巧。 Jeffrey Richter 在MSDN Concurrency Affairs 中有一篇很好的介绍性文章。

【讨论】:

以上是关于C# 中的密集文件 I/O 和数据处理的主要内容,如果未能解决你的问题,请参考以下文章

CPU-bound(计算密集型) 和I/O bound(I/O密集型)/数据密集型

CPU密集型和I/O密集型区别

使用线程池和BlockingQueue重新构建I / O密集型Java Web服务

NodeJS基础入门

线程池大小选择:针对 I/O 密集型场景和 CPU 密集型场景

I/O密集型进程大量进程的场景以及上下文切换