为使用者使用具有限制选项的BufferBlock

时间:2014-10-02 19:08:18

标签: c# task-parallel-library tpl-dataflow

在我的生产者 - 消费者应用程序中,我将BufferBlock定义为添加项目的队列。

 public static BufferBlock<AppointmentReminder> m_Queue = new BufferBlock<AppointmentReminder>();
 SemaphoreSlim seaphore = new SemaphoreSlim(4);

然后要将项目添加到队列中,我有

    private static void Producer()
    {
        for (int i = 0; i < 5000; i++)
        {
            AppointmentReminder reminder = new AppointmentReminder();
            reminder.UniqueId = Guid.NewGuid();
            reminder.CallMethod = "Number";
            reminder.sString = "1234567890";
            m_Queue.Post(reminder);
        }
        for (int i = 0; i < 3000; i++)
        {
            AppointmentReminder reminder = new AppointmentReminder();
            reminder.UniqueId = Guid.NewGuid();
            reminder.CallMethod = "Letter";
            reminder.sString = "abcdefghij";
            m_Queue.Post(reminder);
        }
        for (int i = 0; i < 2000; i++)
        {
            AppointmentReminder reminder = new AppointmentReminder();
            reminder.UniqueId = Guid.NewGuid();
            reminder.CallMethod = "Mixed";
            reminder.sString = "abcd12345y";
            m_Queue.Post(reminder);
        }
        Console.WriteLine("There are {0} items in the queue.\n", m_Queue.Count);
    }

现在我必须处理消费者的一部分。有一种方法RunScript(AppointmentReminder callData)可以做到这一点。这意味着如果项目可用,我们需要在消费者部分中调用该方法。但是有一个节流限制。最大处理项目随时为4个。

所以我有:

    private async static Task Consumer()
    {
        try
        {
            while (await m_Queue.OutputAvailableAsync())
            {
                AppointmentReminder reminder = m_Queue.Receive();
                Call d = new Call();
                d.RunScript(reminder);
            }

        }
        catch (NullReferenceException ex)
        {
            Console.WriteLine("NullReferenceException: " + ex.Message);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

对于种族生产者和消费者,

    static void Main(string[] args)
    {
        AliveEvent = new ManualResetEvent(false);
        Producer(); 
        var consumer = Consumer();
        consumer.Wait();        
    }

我的问题是我对Task Parallel Library (TPL).不强,如何将限制约束应用于消费者?

编辑:2014年10月3日:

基于svick的解决方案。消费者的代码是:

    private async static Task Consumer()
    {
        try
        {
            while (await m_Queue.OutputAvailableAsync())
            {
                var consumerBlock = new ActionBlock<AppointmentReminder>(
remainder => new Call().RunScript(remainder),
new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 4 });
                m_Queue.LinkTo(
consumerBlock, new DataflowLinkOptions { PropagateCompletion = true });
                m_Queue.Complete();
                consumerBlock.Completion.Wait();
            }
            // m_Queue is a static BufferBlock in the original code.
        }

1 个答案:

答案 0 :(得分:2)

比自己编写消费者更好的选择是创建一个ActionBlock,它已经支持限制并行性:

var consumerBlock = new ActionBlock<AppointmentReminder>(
    remainder => new Call().RunScript(remainder),
    new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 4 });

然后将其链接到队列:

queue.LinkTo(
    consumerBlock, new DataflowLinkOptions { PropagateCompletion = true });

最后,等待它完成:

queue.Complete();
consumerBlock.Completion.Wait();