【问题标题】:Do I need two queues for producer-consumer pattern?生产者-消费者模式需要两个队列吗?
【发布时间】:2014-08-07 02:19:58
【问题描述】:

我很难理解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) 来替换它,我该怎么办?

【问题讨论】:

  • 链接到那个旧答案。但一般来说,P/C 只需要 1 个队列。
  • 这已经使用了 TPL。和并发集合。
  • @HenkHolterman,我添加了链接。

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


【解决方案1】:

Producer-consumer 是一个定义了两个参与者的模型:

  1. 创造物品的人 - 生产者
  2. 处理这些物品的人 - 消费者

有不同的方式来组织它们的互操作,但最简单的一种是队列——生产者将新项目入队,消费者将它们出队。

上面显示的代码示例实际上包含三个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同时(worker方法):

        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);
        }
    

这不是生产者 - 消费者 - 它是在两个顺序连接的生产者 - 消费者系统上组织的传送器“模式”。

所以,答案:

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

关于old answer

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

【讨论】:

    猜你喜欢
    • 2018-10-10
    • 2019-05-18
    • 1970-01-01
    • 2012-01-28
    • 2023-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多