![](/img/trans.png)
[英]Converting my C# BlockingCollection based code to TPL dataflow
[英]Deadlocks when using BlockingCollection<T> and TPL dataflow together
我写了一个复制问题的示例测试。 这不是我的实际代码,我试着写一个小的repro。 如果你将边界容量增加到迭代次数有效地给它没有边界,它就不会死锁,如果你把max parallelism放到像1这样的小数字,它就不会死锁。
同样,我知道下面的代码不是很好,但我实际发现的代码更大,难以理解。 基本上,存在与远程资源的连接的阻塞对象池,并且流中的若干块使用了连接。
关于如何解决这个问题的任何想法? 乍一看,它似乎是数据流的问题。 当我打破看看线程时,我看到许多线程被阻塞在Add和0线程被阻塞。 addBlocks出站队列中有几个项尚未传播到takeblock,因此它被卡住或死锁。
var blockingCollection = new BlockingCollection<int>(10000);
var takeBlock = new ActionBlock<int>((i) =>
{
int j = blockingCollection.Take();
}, new ExecutionDataflowBlockOptions()
{
MaxDegreeOfParallelism = 20,
SingleProducerConstrained = true
});
var addBlock = new TransformBlock<int, int>((i) =>
{
blockingCollection.Add(i);
return i;
}, new ExecutionDataflowBlockOptions()
{
MaxDegreeOfParallelism = 20
});
addBlock.LinkTo(takeBlock, new DataflowLinkOptions()
{
PropagateCompletion = true
});
for (int i = 0; i < 100000; i++)
{
addBlock.Post(i);
}
addBlock.Complete();
await addBlock.Completion;
await takeBlock.Completion;
TPL Dataflow并不适用于阻塞很多的代码,我认为这个问题源于此。
我无法弄清楚究竟发生了什么,但我认为解决方案是使用非阻塞集合。 方便的是,Dataflow以BufferBlock
的形式为您提供了一个。 有了它,您的代码将如下所示:
var bufferBlock = new BufferBlock<int>(
new DataflowBlockOptions { BoundedCapacity = 10000 });
var takeBlock = new ActionBlock<int>(
async i =>
{
int j = await bufferBlock.ReceiveAsync();
}, new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 20,
SingleProducerConstrained = true
});
var addBlock = new TransformBlock<int, int>(
async i =>
{
await bufferBlock.SendAsync(i);
return i;
}, new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 20
});
虽然我发现你的代码的整个设计是可疑的。 如果要发送一些其他数据以及块的正常结果,请将该块的输出类型更改为包含该附加数据的类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.