我有一个BlockingCollection(ConcurrentBag,50000),我试图为生产者线程使用一个非常小的有界容量50,000,以便最大化我可以在我的消费者线程的ConcurrentDictionary中处理的记录数。生产者比消费者快得多,并且会消耗大部分内存。
不幸的是,我立刻注意到我的ConcurrentDictionary中的记录总数现在大大低于在我的测试数据执行时添加有限容量50,000后的记录。我读到BlockingCollection的.add方法应该无限期地阻塞,直到集合中有空间来执行add。但是,情况似乎并非如此。
问题:
如果在BlockingCollection中的容量释放之前调用了太多的add,那么BlockingCollection的.add方法最终是否会超时或无声地失败?
如果对#1的回答是肯定的,那么在超出限制容量而不丢失数据后我可以尝试多少次添加?
如果调用了许多正在等待/阻塞容量并且调用了CompleteAdding()方法的BlockingCollection .add()方法,那些等待/阻塞添加会继续等待,然后最终添加或者它们默默地失败?
答案 0 :(得分:9)
如果您正在使用BlockingCollection和ConcurrentDictionary,请确保您的代码中没有隐藏的BlockingCollection.TryAdd(myobject)方法,并将其误认为是ConcurrentDictionary.TryAdd()方法。如果已超过BlockingCollection的边界容量,则BlockingCollection.TryAdd(myobject)将返回false并丢弃生成“静默失败”的添加请求。
关于效果的最终说明
与在同一进程中不使用Bounding Capacity和.TryAdd()相比,在BlockingCollection上使用Bounding Capacity和.Add()似乎(在我自己的情况下无论如何)。
通过实施自己的边界容量策略,我获得了更好的性能结果。有很多方法可以做到这一点。三个选项包括与Monitor.PulseAll()一起使用的Thread.Sleep(),Thread.Spinwait()或Monitor.Wait()。当使用其中一个策略时,也可以使用BlockingCollection.TryAdd()而不是BlockingCollection.Add()并且没有限制容量而不会丢失任何数据或内存不足。这种方法似乎也能产生更好的性能。
您可以根据哪种方案最适合生产者和消费者线程中的速度差异,从三个示例中进行选择。
Thread.Wait()示例:
//Check to see if the BlockingCollection's bounded capacity has been exceeded.
while (Tokens.Count > 50000)
{ //If the bounded capacity has been exceeded
//place the thread in wait mode
Thread.Sleep(SleepTime);
}
Thread.SpinWait()示例:
//Check to see if the BlockingCollection's bounded capacity has been exceeded.
while (Tokens.Count > 50000)
{ //If the capacity has been exceeded
//place the thread in wait mode
Thread.SpinWait(SpinCount);
}
Monitor.Wait()示例
此示例在Producer和Consumer方面都需要一个钩子。
制片人代码
//Check to see BlockingCollection capacity has been exceeded.
if (Tokens.Count > 50000)
{
lock (syncLock)
{ //Double check before waiting
if (Tokens.Count > 50000)
{
Monitor.Wait(syncLock, 1000);
}
}
}
消费者代码
//Check to see BlockingCollection capacity is back a normal range.
if (Tokens.Count <= 40000)
{
lock (syncLock)
{ //Double check before waiting
if (Tokens.Count < 40000)
{
Monitor.PulseAll(syncLock);
}
}
}