生产者 - 消费者模式需要两个队列吗?

时间:2014-08-06 17:57:18

标签: c# .net-4.0 .net-4.5

我很难理解BlockingCollection。 以下代码来自old answer,但它使用了两个队列。

using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;

namespace Demo
{
    class Program
    {
        static void Main(string[] args)
        {
            new Program().run();
        }

        void run()
        {
            int threadCount = 4;
            Task[] workers = new Task[threadCount];

            Task.Factory.StartNew(consumer);

            for (int i = 0; i < threadCount; ++i)
            {
                int workerId = i;
                Task task = new Task(() => worker(workerId));
                workers[i] = task;
                task.Start();
            }

            for (int i = 0; i < 100; ++i)
            {
                Console.WriteLine("Queueing work item {0}", i);
                inputQueue.Add(i);
                Thread.Sleep(50);
            }

            Console.WriteLine("Stopping adding.");
            inputQueue.CompleteAdding();
            Task.WaitAll(workers);
            outputQueue.CompleteAdding();
            Console.WriteLine("Done.");

            Console.ReadLine();
         }

         void worker(int workerId)
         {
            Console.WriteLine("Worker {0} is starting.", workerId);

            foreach (var workItem in inputQueue.GetConsumingEnumerable())
            {
                Console.WriteLine("Worker {0} is processing item {1}", workerId, workItem);
                Thread.Sleep(100);          // Simulate work.
                outputQueue.Add(workItem);  // Output completed item.
            }

            Console.WriteLine("Worker {0} is stopping.", workerId);
        }

        void consumer()
        {
            Console.WriteLine("Consumer is starting.");

            foreach (var workItem in outputQueue.GetConsumingEnumerable())
            {
                Console.WriteLine("Consumer is using item {0}", workItem);
                Thread.Sleep(25);
            }

            Console.WriteLine("Consumer is finished.");
        }

            BlockingCollection<int> inputQueue = new BlockingCollection<int>();
            BlockingCollection<int> outputQueue = new BlockingCollection<int>();
       }
    }

我可以只使用一个队列吗?如果使用.net 4.5(TPL)替换它,我该怎么办?

1 个答案:

答案 0 :(得分:2)

Producer-consumer是一个定义两个角色的模型:

  1. 创建项目的人 - 制作人
  2. 处理这些项目的人 - 消费者
  3. 组织互操作有不同的方法,但最简单的方法是Queue - 生产者将新项目排入其中,消费者将它们排队。

    上面显示的代码示例实际上包含三个actor和两个队列:

    1. 制片人1(在主页中)

          for (int i = 0; i < 100; ++i)
          {
              Console.WriteLine("Queueing work item {0}", i);
              inputQueue.Add(i);
              Thread.Sleep(50);
          }
      
    2. 消费者1和生产者2同时(工人方法):

          foreach (var workItem in inputQueue.GetConsumingEnumerable())
          {
              Console.WriteLine("Worker {0} is processing item {1}", workerId, workItem);
              Thread.Sleep(100);          // Simulate work.
              outputQueue.Add(workItem);  // Output completed item.
          }
      
    3. 消费者2(消费者方法):

          foreach (var workItem in outputQueue.GetConsumingEnumerable())
          {
              Console.WriteLine("Consumer is using item {0}", workItem);
              Thread.Sleep(25);
          }
      
    4. 这不是生产者 - 消费者 - 它是由两个连续生产者 - 消费者系统组织的传送带“模式”。

      所以,答案:

      不,不需要使用两个队列。您可以将示例缩减为适当的单级生产者 - 使用者,只需删除worker方法并在inputQueue上使用consumer方法操作。

      关于old answer

      旧问题不涉及生产者 - 消费者 - 它涉及输送机模型 - 数据流。简单的生产者 - 消费者不需要任何复杂的多级数据转换。