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

5
我正在编写一个应用程序,需要处理一个大型文本文件(逗号分隔,包含几种不同类型的记录 - 我没有更改数据存储格式的能力或意愿)。它会读取记录(通常是按顺序读取文件中的所有记录,但并非总是如此),然后将每个记录的数据传递给某些处理过程。
目前,该应用程序的这一部分是单线程的(读取记录,处理它,读取下一个记录等)。我认为,在一个线程中将记录以队列的形式读取,并在另一个线程中以小块或当它们可用时进行处理可能更有效。
我不知道如何开始编写这样的程序,包括所需的数据结构以及如何正确实现多线程。有人可以提供任何指导,或提供其他关于如何提高性能的建议吗?

请查看CodeProject上的这篇文章这里,以及Filehelpers.com上的内容。 - t0mm13b
你知道你大部分时间是花在阅读还是处理上吗?我猜想应该是后者。根据情况,你可能希望优化处理过程。例如,如果你的处理过程涉及写入文件或数据库,如果可以的话最好批量进行。 - Chris Haas
这要看情况...我会说大约15%到40%的时间用于处理。实际上,需要处理的内容并不是很多。当然,我会尝试进一步优化这个阶段,但我知道这个应用程序会从多线程中受益。 - We Are All Monica
3个回答

3

如果你能平衡处理记录的时间和读取记录的时间,你可能会受益。这种情况下,你可以使用生产者/消费者设置,例如同步队列和一个工作者(或几个)出队和处理。我也会倾向于研究并行扩展;很容易编写你的读取代码的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]);
        }
    }
}

你的阻塞队列似乎是我正在寻找的,谢谢。我今天会尝试一下。 - We Are All Monica
一个无锁队列怎么样:http://www.boyet.com/Articles/LockfreeQueue.html?在我的情况下,这会有所改善吗?我如何使用分析器来确定等待其他线程释放锁的时间? - We Are All Monica

1

1

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

不幸的是,在C#中编写异步操作有点麻烦。有一个MSDN示例,但它并不好。使用异步工作流可以很好地解决这个问题。我写了一篇文章,解释了这个问题,并展示了如何使用C#迭代器进行类似的操作。

C#的更有前途的解决方案是Wintellect PowerThreading库,它支持使用C#迭代器进行类似的操作。Jeffrey Richter在MSDN Concurrency Affairs上写了一篇很好的介绍文章。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接