【发布时间】:2017-09-09 16:58:30
【问题描述】:
我想使用类似于问题here 和代码here 的连续运行的BufferBlock 来实现消费者/生产者模式。
我尝试使用像 OP 这样的 ActionBlock,但如果缓冲区已满且新消息在其队列中,则新消息永远不会添加到 ConcurrentDictionary _queue。
在下面的代码中,当使用此调用将新消息添加到缓冲区块时,永远不会调用 ConsumeAsync 方法:_messageBufferBlock.SendAsync(message)
如何更正下面的代码,以便在每次使用 _messageBufferBlock.SendAsync(message) 添加新消息时调用 ConsumeAsync 方法?
public class PriorityMessageQueue
{
private volatile ConcurrentDictionary<int,MyMessage> _queue = new ConcurrentDictionary<int,MyMessage>();
private volatile BufferBlock<MyMessage> _messageBufferBlock;
private readonly Task<bool> _initializingTask; // not used but allows for calling async method from constructor
private int _dictionaryKey;
public PriorityMessageQueue()
{
_initializingTask = Init();
}
public async Task<bool> EnqueueAsync(MyMessage message)
{
return await _messageBufferBlock.SendAsync(message);
}
private async Task<bool> ConsumeAsync()
{
try
{
// This code does not fire when a new message is added to the buffereblock
while (await _messageBufferBlock.OutputAvailableAsync())
{
// A message object is never received from the bufferblock
var message = await _messageBufferBlock.ReceiveAsync();
}
return true;
}
catch (Exception ex)
{
return false;
}
}
private async Task<bool> Init()
{
var executionDataflowBlockOptions = new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = Environment.ProcessorCount,
BoundedCapacity = 50
};
var prioritizeMessageBlock = new ActionBlock<MyMessage>(msg =>
{
SetMessagePriority(msg);
}, executionDataflowBlockOptions);
_messageBufferBlock = new BufferBlock<MyMessage>();
_messageBufferBlock.LinkTo(prioritizeMessageBlock, new DataflowLinkOptions { PropagateCompletion = true, MaxMessages = 50});
return await ConsumeAsync();
}
}
编辑 我已经删除了所有额外的代码并添加了 cmets。
【问题讨论】:
-
你能做一个非工作代码的最小例子吗?这太多了,无法得到答案。
-
@VMAtm 请看一下更新后的代码
-
您不需要调用
OutputAvailableAsync或ReceiveAsync,您的块已经链接,并且会在您发送消息时传播消息。当前代码中的任何内容实际上都不会向您的管道发送消息。你可以简单地删除ConsumeAsync它在这里没有任何意义。 -
@JSteward 我删除了每个 VMAtm 请求的代码。这是一个长时间运行的过程,缓冲块会间歇性地接收输入消息。我需要知道新消息何时到达,这就是为什么我在做 while (await _messageBufferBlock.OutputAvailableAsync())
-
如果您需要在收到每条新消息时运行代码,您可以将
BufferBlock替换为TransformBlock并使用它的委托来运行您需要的内容。
标签: c# multithreading task-parallel-library tpl-dataflow bufferblock