C# 如何正确使用BlockingCollection.GetConsumingEnumerable?

C# 如何正确使用BlockingCollection.GetConsumingEnumerable?,c#,task-parallel-library,producer-consumer,blockingcollection,C#,Task Parallel Library,Producer Consumer,Blockingcollection,我试图使用BlockingCollection实现生产者/消费者模式,因此我编写了一个简单的控制台应用程序来测试它 public class Program { public static void Main(string[] args) { var workQueue = new WorkQueue(); workQueue.StartProducingItems(); workQueue.StartProcessingItems

我试图使用
BlockingCollection
实现生产者/消费者模式,因此我编写了一个简单的控制台应用程序来测试它

public class Program
{
    public static void Main(string[] args)
    {
        var workQueue = new WorkQueue();
        workQueue.StartProducingItems();
        workQueue.StartProcessingItems();

        while (true)
        {

        }
    }
}

public class WorkQueue
{
    private BlockingCollection<int> _queue;
    private static Random _random = new Random();

    public WorkQueue()
    {
        _queue = new BlockingCollection<int>();

        // Prefill some items.
        for (int i = 0; i < 100; i++)
        {
            //_queue.Add(_random.Next());
        }
    }

    public void StartProducingItems()
    {
        Task.Run(() =>
        {
            _queue.Add(_random.Next()); // Should be adding items to the queue constantly, but instead adds one and then nothing else.
        });
    }

    public void StartProcessingItems()
    {
        Task.Run(() =>
        {
            foreach (var item in _queue.GetConsumingEnumerable())
            {
                Console.WriteLine("Worker 1: " + item);
            }
        });

        Task.Run(() =>
        {
            foreach (var item in _queue.GetConsumingEnumerable())
            {
                Console.WriteLine("Worker 2: " + item);
            }
        });
    }
}

GetConsumingEnumerable()
正在阻塞。如果要不断添加到队列中,应将调用放入
\u队列。将
添加到循环中:

public void StartProducingItems()
{
    Task.Run(() =>
    {
        while (true)
            _queue.Add(_random.Next());
    });
}
关于
Main()
方法,您可以调用
Console.ReadLine()
方法来防止主线程在按下键之前结束:

public static void Main(string[] args)
{
    var workQueue = new WorkQueue();
    workQueue.StartProducingItems();
    workQueue.StartProcessingItems();

    Console.WriteLine("Press a key to terminate the application...");
    Console.ReadLine();
}

GetConsumingEnumerable()
正在阻塞。如果要不断添加到队列中,应将调用放入
\u队列。将
添加到循环中:

public void StartProducingItems()
{
    Task.Run(() =>
    {
        while (true)
            _queue.Add(_random.Next());
    });
}
关于
Main()
方法,您可以调用
Console.ReadLine()
方法来防止主线程在按下键之前结束:

public static void Main(string[] args)
{
    var workQueue = new WorkQueue();
    workQueue.StartProducingItems();
    workQueue.StartProcessingItems();

    Console.WriteLine("Press a key to terminate the application...");
    Console.ReadLine();
}


制作人应该不断添加项目,但它会添加一个项目,然后再也不会添加。这一项然后由一个消费者处理。然后,两个消费者都会阻止等待添加项目,但没有一个消费者是这样的。你还期待什么?消费者会被阻止,直到物品被添加,这就是为什么它被称为阻止收集不,问题是生产者添加了一个物品,然后停止。这就是你编码它的方式。您正在启动一项添加单个项目的任务。你是不是少了一个环什么的?我是个白痴。谢谢。哈哈,当你的鼻子在你的代码里的时候,它总是发生。对于一个外部读者来说,这是如此的明显,以至于我不确定你在
中要去哪里,制作人应该不断地添加项目,但是它添加了一个项目,然后再也不会添加了。这一项然后由一个消费者处理。然后,两个消费者都会阻止等待添加项目,但没有一个消费者是这样的。你还期待什么?消费者会被阻止,直到物品被添加,这就是为什么它被称为阻止收集不,问题是生产者添加了一个物品,然后停止。这就是你编码它的方式。您正在启动一项添加单个项目的任务。你是不是少了一个环什么的?我是个白痴。谢谢。哈哈,当你的鼻子在你的代码里的时候,它总是发生。对于外部读者来说,这是如此的明显,以至于我不确定你要去哪里。只要我按下回车键,它就会结束。一定有更好的办法。也许制作StartProducingItems应该是异步的?@user9993公开您在
StartProcessingItems
中创建的任务,然后在
Main()
中对其调用
.Wait()
。如果您有多个工作线程,则使用
task.whalll
创建一个聚合任务并将其公开,如果您公开了WorkQueue类中的任务,则可以等待这些任务。但是,你将如何告诉制作人停止制作?因为你的程序所做的一切似乎都是制作和消费BlockingCollection中的项目,所以等待任务没有多大意义。我想,您也可以在生产者停止生产时立即终止应用程序。@mm8
completedadding
必须在生产者完成生产时调用,但是消费者需要更多的时间来完成最后一项的处理。因此,等待必须在消费者身上完成,而不是在生产商身上。只要我按下回车键,等待就会结束。一定有更好的办法。也许制作StartProducingItems应该是异步的?@user9993公开您在
StartProcessingItems
中创建的任务,然后在
Main()
中对其调用
.Wait()
。如果您有多个工作线程,则使用
task.whalll
创建一个聚合任务并将其公开,如果您公开了WorkQueue类中的任务,则可以等待这些任务。但是,你将如何告诉制作人停止制作?因为你的程序所做的一切似乎都是制作和消费BlockingCollection中的项目,所以等待任务没有多大意义。我想,您也可以在生产者停止生产时立即终止应用程序。@mm8
completedadding
必须在生产者完成生产时调用,但是消费者需要更多的时间来完成最后一项的处理。因此,等待必须是消费者,而不是生产者