我可以限制C#应用程序的I / O.

时间:2010-08-04 17:33:32

标签: c# multithreading io

我构建了一个应用程序,可以对数千个文件执行操作,然后将这些文件的修改后的副本写入磁盘。我正在使用ThreadPool,但它产生了如此多的线程,因为PC总共没有响应260,所以我将默认值250的最大值更改为50,这解决了这个问题(应用程序仅产生约60个线程),但是现在文件已经变得如此快速地准备好了,它将UI绑定到了电脑没有响应的程度。

有没有办法限制I / O的数量 - 我的意思是,我喜欢使用50个线程来执行文件的工作,而不是50个线程在处理它们的同时写入。如果我可以保留它,我宁愿不重新构建文件部分的编写 - 我希望我可以限制此池中的线程可以消耗的I / O数量(同时)。

2 个答案:

答案 0 :(得分:7)

使用信号量来限制否。想要同时写入磁盘的线程。

http://msdn.microsoft.com/en-us/library/system.threading.semaphore.aspx

  

限制可以的线程数   访问资源或资源池   同时进行。

答案 1 :(得分:4)

你真的不需要那么多线程。磁盘只能支持其最大读取和写入吞吐量,如果单个线程专用于IO(即读取或写入),则单个线程可以轻松地最大化。您也无法同时读取和写入硬盘(虽然这对于OS缓存层等很复杂),因此并发线程的读取和写入可能会适得其反。对于非IO任务而言,拥有比处理器\核心更多的线程也几乎没有什么收获,因为任何额外的线程将花费大量时间等待核心变得可用,例如如果你有50个线程和4个核心,那么在任何给定时间,至少有46个线程将处于空闲状态。浪费的线程将导致内存消耗也会导致性能开销,因为他们都会争取在某个时间在核心上获得破解,并且操作系统必须仲裁这场战斗。

更简单的方法是使用单个线程,其作用是读取文件,然后将数据添加到阻塞队列(例如,参见ConcurrentQueue),同时拥有多个工作线程等待队列中的文件数据(例如,数字线程等于处理器\核心数)。这些工作线程将在添加项目时在队列中咀嚼,并在其为空时阻塞。当工作线程完成一项工作时,它可以将其添加到另一个阻塞队列,该队列由读取器线程或专用编写器线程监视。它的工作是将文件写出来。

这种模式试图在一小部分协作线程中平衡IO和CPU,其中IO线程的数量仅限于硬盘驱动器的物理能力,以及许多合理的CPU工作线程对于您拥有的处理器\核心数量。从本质上讲,它将IO和CPU工作分开,以便事物的行为更具可预测性。

除此之外,如果IO真的是问题(并没有大量的线程都互相争斗),那么你可以在你的文件中放置一些暂停(例如Thread.Sleep)读写线程以限制多少他们做的工作。

<强>更新

也许值得解释为什么首先会生成如此多的线程。这是线程池使用的退化情况,并且以排队工作项为中心,其中包含IO组件。

线程池从其队列中执行工作项,并监视正在执行的工作项的执行时间。如果当前正在执行的工作项需要很长时间才能完成(我认为距离内存只有半秒),那么它将开始向池添加更多线程,因为它认为这将使队列处理得更快\更公平。但是,如果其他并发工作项也在对共享磁盘执行工作IO,则磁盘的性能实际上会降低,这意味着工作项将花费更长的时间来执行。由于工作项执行时间较长,因此线程池会添加更多线程。这是退化的情况,随着更多线程的添加,性能变得越来越差。

建议使用信号量必须小心,因为信号量可能导致线程池线程被阻塞,线程池会看到工作项需要很长时间才能执行,并且它仍然会开始添加更多线程。