![](/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.