我需要遍历一个大型列表,并为每个项目调用一个Web服务来获取一些数据。但是,我希望限制对WS的请求数量,以表示任何时候执行的并发请求不超过5个。所有对WS的调用都是使用async/await
进行的。我正在使用TPL数据流BufferBlock
,其中BoundedCapacity
为5.一切正常,但我注意到的是等待WS调用的消费者阻塞队列直到完成导致所有缓冲区块中的请求是串行执行的。是否有可能让消费者一次总共处理5个项目?或者我是否需要设置多个消费者或开始研究动作块?所以简而言之,我想用5个项目为队列播种。当一个项目被处理时,第六个将取代它,所以我总是有5个并发请求,直到没有更多的项目要处理。
我用这个作为我的向导:Async Producer/Consumer Queue using Dataflow
感谢您的帮助。以下是代码的简化版本
//set up
BufferBlock<CustomObject> queue = new BufferBlock<CustomObject>(new DataflowBlockOptions { BoundedCapacity = 5 });
var producer = QueueValues(queue, values);
var consumer = ConsumeValues(queue);
await Task.WhenAll(producer, consumer, queue.Completion);
counter = await consumer;
//producer
function QueueValues(BufferBlock<CustomObject> queue, IList<CustomObject> values)
{
foreach (CustomObject value in values)
{
await queue.SendAsync(value);
}
queue.Complete();
}
//consumer
function ConsumeValues(BufferBlock<CustomObject> queue)
{
while (await queue.OutputAvailableAsync())
{
CustomObject value = await queue.ReceiveAsync();
await CallWebServiceAsync(value);
}
}
答案 0 :(得分:2)
您对TPL Dataflow的使用相当奇怪。通常,您会将消耗和处理移动到流程中。附加TransformBlock
以调用Web服务。删除ConsumeValues
。
ConsumeValues
按顺序执行,这根本不是你想要的。
而不是BoundedCapacity
我认为您更愿意MaxDegreeOfParallelism
。
答案 1 :(得分:2)
您应该使用ActionBlock
并将MaxDegreeOfParallelism
设置为5.您可能还需要设置BoundedCapacity
,但这是为了限制生产者而不是消费者:
var block = new ActionBlock<CustomObject>(
item => CallWebServiceAsync(item),
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 5,
BoundedCapacity = 1000
});
foreach (CustomObject value in values)
{
await block.SendAsync(value);
}
block.Complete();
await block.Completion;