【发布时间】:2016-12-20 11:35:19
【问题描述】:
我在我的应用中实现了使用 TPL 数据流的生产者/消费者模式。我有一个包含大约 40 个块的大数据流网格。网格中有两个主要的功能部分:生产者部分和消费者部分。生产者应该不断地为消费者提供大量工作,而消费者有时会缓慢地处理传入的工作。当消费者忙于某些指定数量的工作项时,我想暂停生产者。否则应用程序会消耗大量内存/CPU 并且行为不可持续。
我制作了演示该问题的演示应用程序:
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
namespace DataflowTest
{
class Program
{
static void Main(string[] args)
{
var options = new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 4,
EnsureOrdered = false
};
var boundedOptions = new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 4,
EnsureOrdered = false,
BoundedCapacity = 5
};
var bufferBlock = new BufferBlock<int>(boundedOptions);
var producerBlock = new TransformBlock<int, int>(x => x + 1, options);
var broadcastBlock = new BroadcastBlock<int>(x => x, options);
var consumerBlock = new ActionBlock<int>(async x =>
{
var delay = 1000;
if (x > 10) delay = 5000;
await Task.Delay(delay);
Console.WriteLine(x);
}, boundedOptions);
producerBlock.LinkTo(bufferBlock);
bufferBlock.LinkTo(broadcastBlock);
broadcastBlock.LinkTo(producerBlock);
broadcastBlock.LinkTo(consumerBlock);
bufferBlock.Post(1);
consumerBlock.Completion.Wait();
}
}
}
应用程序打印如下内容:
2
1
3
4
5
69055
69053
69054
69057
438028
438040
142303
438079
这意味着生产者不断旋转并将消息推送给消费者。我希望它暂停并等到消费者完成当前部分工作,然后生产者应该继续为消费者提供消息。
我的问题与其他question 类似,但没有得到正确回答。我尝试了该解决方案,但它在这里不起作用,允许生产者向消费者发送消息。同样设置BoundedCapacity 也不起作用。
到目前为止,我认为唯一的解决方案是制作我自己的块来监控目标块队列并根据目标块的队列进行操作。但我希望这对于这个问题来说有点过头了。
【问题讨论】:
-
您是否考虑过改用
Rx?看看这个答案:stackoverflow.com/questions/2542764/tpl-vs-reactive-framework -
我希望不需要这个,因为在 Dataflow 上花费了很多时间,它非常适合我的需求。
-
在您的演示中,生产者可以自己生成所有消息,而无需通过广播块接收自己的消息。你的真实代码也是这样吗,还是需要生产者→生产者周期?
-
@svick 但是如果我将生产者链接到自身,消费者将如何从生产者那里获取数据?真正的生产者周期由一堆块组成,它们实际加载顺序评论页面、解析页面并将 cmets 传递给消费者。
-
@kseen 我在问广播→制作人链接是否必要,或者是否可以避免。
标签: c# .net task-parallel-library tpl-dataflow dataflow