我制作了由4个生产者-消费者线程组成的链(形成4个步骤的管道)。令我惊讶的是,所有四个线程都按顺序运行,而不是同时运行!!!也就是说,第二个线程神秘地等待直到第一个线程完全完成生成为止。第三个线程神秘地等待直到第二个线程完全完成生成(依此类推)。
情况变得更糟。如果我将Thread.Sleep(300)放入第一个生产者的循环中,则其他三个线程将并发并实际上获得处理器时间,如预期的那样,并从多线程应用程序产生预期的“随机交错”控制台输出。我几乎无法接受“ sleep ”是解决方案的必要部分的想法,但是我看到code written by Jon Skeet正是以这种方式合并了 sleep 。
请告诉我,实现并发不是必需的,如果是并发,那么为什么是?
关于我的特定生产者-消费者链的一个更精确的故事看起来像这样:
要通过此管道处理100万个小部件,大约需要4分钟。在4分钟内,有足够的时间安排最后3个线程,并与第一个线程同时进行一些工作。但是正如我说的那样,最后三个线程是按顺序运行的,除非我为第一个线程引入了微小的 sleep 。这没有道理。
对为什么这样工作有任何想法吗?
p.s.请不要告诉我,正如我所描述的,长长的生产者-消费者链可以被缩减或消除。请相信我(或假设)我需要那么长的链条。 :)
最佳答案
紧密循环会影响多线程。听起来您的第一个线程运行得足够快,以至于第二个线程甚至没有机会启动。 请注意,如果发生这种情况,那么顺序解决方案是最有效的。 :)
由于您的生产者/消费者布局有些复杂,因此我假设您在实际数据中看不到此行为。
尽管可以通过添加带有非零参数的Thread.Sleep
(请参阅Joe Duffy's blog entry on why this works)来解决此问题,或者只是忽略它,但是更好的解决方案是限制第一个生产者/消费者队列的大小。这将只允许第一个线程产生一定数量的小部件,然后阻塞直到管道的其余部分有机会启动。
.NET 4.0 BlockingCollection<T>
允许您指定最大大小。 Microsoft Rx library已将其反向移植到.NET 3.5,因此您可以根据需要使用它。 (我建议这样做,而不要使用内部解决方案)。
关于.net - .NET中的生产者消费者链和线程调度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3535276/