Streaming Data BlockingCollection

时间:2012-01-28 11:51:21

标签: c# streaming blockingcollection

Stephen Toub的书第88页

http://www.microsoft.com/download/en/details.aspx?id=19222

有代码

private BlockingCollection<T> _streamingData = new BlockingCollection<T>();
// Parallel.ForEach
Parallel.ForEach(_streamingData.GetConsumingEnumerable(),
item => Process(item));
// PLINQ
var q = from item in _streamingData.GetConsumingEnumerable().AsParallel()
...
select item;
然后斯蒂芬提到

  

“时   将调用GetConsumingEnumerable作为数据源的结果传递给Parallel.ForEach,使用的线程   当集合变空时,循环有可能阻塞。并且Parallel.ForEach可能无法将阻塞的线程释放回ThreadPool以用于退役或其他用途。因此,使用如图所示的代码   如上所述,如果集合为空的任何时间段,则该过程中的线程数可能会稳定   生长;“

我不明白为什么线程数会增长?

如果集合为空,那么blockingcollection不会请求任何其他线程吗?

因此,您不需要使用WithDegreeOfParallelism来限制BlockingCollection上使用的线程数

1 个答案:

答案 0 :(得分:3)

线程池有一个爬山算法,用于估计适当的线程数。只要添加线程增加了吞吐量,线程池就会创建更多线程。它会假设发生了一些阻塞或IO,并试图通过超过系统中处理器的数量来使CPU饱和。

这就是在线程池线程上执行IO和阻塞内容可能很危险的原因。

以下是所述行为的完整工作示例:

        BlockingCollection<string> _streamingData = new BlockingCollection<string>();

        Task.Factory.StartNew(() =>
            {
                for (int i = 0; i < 100; i++)
                {
                    _streamingData.Add(i.ToString());
                    Thread.Sleep(100);
                }
            });

        new Thread(() =>
            {
                while (true)
                {
                    Thread.Sleep(1000);
                    Console.WriteLine("Thread count: " + Process.GetCurrentProcess().Threads.Count);
                }
            }).Start();

        Parallel.ForEach(_streamingData.GetConsumingEnumerable(), item =>
            {
            });

我不知道为什么线程计数不断攀升,尽管它不会增加吞吐量。根据我解释的模型,它不会增长。但我不知道我的模型是否真的正确。

也许线程池有一个额外的启发式,如果它看不到任何进展(在每秒完成的任务中测量),它就会产生线程。这是有道理的,因为这可能会阻止应用程序中的大量死锁。如果重要任务无法运行,则会发生死锁,因为它们正在等待现有任务退出并使线程可用。这是线程池的一个众所周知的问题。

相关问题