我有一个长时间运行的进程,它读取大文件并写入摘要文件。为了加快速度,我使用常规旧线程同时处理多个文件:
ThreadStart ts = new ThreadStart(Work);
Thread t = new Thread(ts);
t.Start();
我发现即使单独的线程读取单独的文件并且它们之间没有锁定并且在24核盒子上使用4个线程,我甚至无法在CPU上达到10%或者在CPU上达到10%磁盘I / O.如果我在我的应用程序中使用更多线程,它似乎运行得更慢。
我猜我做错了,但是好奇的是,如果我第二次和第三次启动整个exe,那么它实际上处理文件的速度提高了两倍和三倍。我的问题是,为什么我不能在我的一个应用程序中获得12个线程来处理数据并对机器征税以及3个我的应用实例中的4个线程?
我已经分析了应用程序,而且最耗时且频繁调用的函数都是字符串处理调用。
答案 0 :(得分:6)
您的计算问题可能不受CPU限制,但I / O受限。说明您的磁盘I / O“仅为10%”并没有帮助。我不确定这种性能计数器是否存在。
在使用更多线程时它变慢的原因是因为这些线程都试图同时到达各自的文件,而磁盘子系统很难尝试容纳所有不同的线程。你看,即使采用像SSD这样的现代技术,其寻道时间比传统硬盘要小几个数量级,但仍然会受到惩罚。
相反,您应该断定您的问题是磁盘绑定的,单个线程可能是解决问题的最快方法。
有人可能会说你可以使用异步技术来处理已读取的位,而在后台读取下一位,但我认为你会看到很少的性能提升。
我不久前在一个小工具中遇到了类似的问题,我想计算硬盘上所有文件的MD5签名,我发现CPU比存储系统太快了我得到了类似的结果试图通过使用更多线程来获得更多性能。
使用任务并行库并没有缓解这个问题。
答案 1 :(得分:2)
首先在一个24核盒子上,如果你只使用4个线程,它可以使用的最大CPU是16.7%,所以你的利用率实际上是60%,这是相当不错的。
很难判断你的程序在这一点上是否受I / O约束,我的猜测是。您需要在项目中运行探查器,并查看项目花费大部分时间的代码段。如果它正在进行读/写操作,则它是I / O绑定的。
你可能会使用某种形式的线程间锁定。这会导致程序在添加更多线程时变慢,是运行第二个进程会解决这个问题,但修复锁定也是如此。
归结为什么是没有分析信息我们不能说如果使用第二个进程会加快速度或减慢速度,我们需要知道程序是否挂起了I / O操作,锁定操作,或者只是花费很长时间才能更好地并行化。
答案 2 :(得分:0)
我认为你发现当一个进程同时在多个文件中写入数据时,哪个文件缓存不理想。当脏页面缓存的数量超过阈值时,文件缓存应同步到磁盘。似乎一个进程中的并发编写器比单线程编写器更快地达到阈值。您可以在此处阅读有关文件系统缓存的内容File Cache Performance and Tuning
答案 3 :(得分:-1)
尝试使用.net 4中的任务库(System.Threading.Task)。该库具有针对不同数量的处理器的内置优化。
不知道你的问题是什么,也许是因为你的代码片段并不真正提供信息