C# 具有并发调度程序的异步生产者-消费者应用程序

C# 具有并发调度程序的异步生产者-消费者应用程序,c#,.net,semaphore,tpl-dataflow,C#,.net,Semaphore,Tpl Dataflow,我正在使用BufferBlock实现生产者-消费者。代码运行良好 static async Task Produce(ITargetBlock<int> queue) { try { // Post messages to the block asynchronously. for (int i = 0; i < 100; i++) { Console.WriteLine("Sending

我正在使用
BufferBlock
实现生产者-消费者。代码运行良好

static async Task Produce(ITargetBlock<int> queue)
{
    try
    {
        // Post messages to the block asynchronously. 
        for (int i = 0; i < 100; i++)
        {
            Console.WriteLine("Sending: {0}", i);
            await queue.SendAsync(i);
        }
    }
    finally 
    {
        queue.Complete();
    }
}

static async Task Consume(ISourceBlock<int> queue)
{
    // Read messages from the block asynchronously. 
    while (await queue.OutputAvailableAsync())
    {
        int value = await queue.ReceiveAsync();
        Console.WriteLine("Receiving: {0}", value);
    }
}

static void Main(string[] args)
{
    // Create a BufferBlock<int> object. 
    var queue = new BufferBlock<int>();

    try
    {
        var produce = Produce(queue);
        var consume = Consume(queue);

        Task.WaitAll(produce, consume, queue.Completion);
    }
    catch (Exception exception)
    {
        Console.WriteLine("An exception was thrown: {0}", exception.Message);
        Console.WriteLine("Terminating...");
    }
}
静态异步任务生成(ITargetBlock队列)
{
尝试
{
//将消息异步发布到块。
对于(int i=0;i<100;i++)
{
WriteLine(“发送:{0}”,i);
等待队列。sendaync(i);
}
}
最后
{
queue.Complete();
}
}
静态异步任务消耗(ISourceBlock队列)
{
//异步读取块中的消息。
while(wait queue.OutputAvailableAsync())
{
int value=wait queue.ReceiveAsync();
WriteLine(“接收:{0}”,值);
}
}
静态void Main(字符串[]参数)
{
//创建一个BufferBlock对象。
var queue=new BufferBlock();
尝试
{
var product=生产(队列);
var消费=消费(队列);
Task.WaitAll(生产、消费、排队、完成);
}
捕获(异常)
{
WriteLine(“引发了异常:{0}”,exception.Message);
控制台写入线(“终止…”);
}
}
现在我有一个节流问题,我希望消费者的最大并发数是4。我想使用
SemaphoreSlim
bot,但不确定如何应用它


注意:这是一个并发调度程序问题,而不是并行性问题

如果您只想一次消费一定量,只需多次调用
TryRecieve
,直到它变为空或达到该量即可。下面是一个扩展方法,用于处理:

public static bool TryReceive<T>(this BufferBlock<T> bufferBlock, int count, out IList<T> items)
{
    items = new List<T>();   
    for (var i = 0; i < count; i++)
    {
        T item;
        if (bufferBlock.TryReceive(out item))
        {
            items.Add(item);
        }
        else
        {
            break;
        }
    }
    return items.Any();
}
publicstaticbooltryreceive(这个BufferBlock,int count,out IList项)
{
项目=新列表();
对于(变量i=0;i
因此,消费者成为:

static async Task Consume(BufferBlock<int> queue)
{
    // Read messages from the block asynchronously. 
    while (await queue.OutputAvailableAsync())
    {
        IList<int> values;
        queue.TryReceive(4, out values);
        Console.WriteLine("Receiving: {0}", string.Join(", ", values));
    }
}
静态异步任务消耗(缓冲块队列)
{
//异步读取块中的消息。
while(wait queue.OutputAvailableAsync())
{
IList值;
queue.TryReceive(4,out值);
WriteLine(“Receiving:{0}”,string.Join(“,”,values));
}
}

你所说的“消费者的并发数”是什么意思?说任何时候我们不能消费超过4件物品。@Love:你为什么不使用
ActionBlock
,并发限制为4件呢?@StephenCleary,我很难理解
ActionBlock
。我认为这是为了并行性而不是一致性。并行性适用于多个cpu核。@有什么理由不希望使用可用的核吗?有几个错误。“方法‘TryReceive’的重载不包含2个参数。并且IList不包含‘Any’…@Love的定义。我的答案中的扩展方法包含2个参数(在它扩展的缓冲块之上).Any是System.Linq命名空间的一部分。因此我需要将其放在单独的类中而不是方法中?这是扩展的含义?@Love yes。扩展方法需要放在静态类中。我将其放在单独的类中。现在错误是
实例参数:无法从“System.Threading.Tasks.Dataflow.ISourceBlock”转换为“Sysye”m、 线程.Tasks.Dataflow.BufferBlock'