【问题标题】:BlockingCollection multiple consumerBlockingCollection 多个消费者
【发布时间】:2012-11-02 12:42:26
【问题描述】:

我有以下代码,其中包含一个生产者线程和多个消费者线程。你知道多个消费者是否是线程安全的。例如,线程 1 是否有可能正在消费,而线程 2 是否并行消费并更改线程 1 中使用的项目的值?

namespace BlockingColl
{
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        try
        {
            for (int i = 0; i < 3; i++)
            {

                ThreadPool.QueueUserWorkItem((x) =>
                   {
                       foreach (var item in bc.GetConsumingEnumerable())
                       {
                           Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " - " + item + " - " + DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss.fff tt"));
                       }
                   });
            }
        }
        catch (Exception)
        {

            throw;
        }
    }

    private void button2_Click(object sender, EventArgs e)
    {
        for (int i = 0; i < 3; i++)
        {

            ThreadPool.QueueUserWorkItem((x) =>
               {
                   Cache.Consume();
               });
        }


        for (int i = 0; i < 50000; i++)
        {
            Cache.bc.TryAdd(new Client() { ClientId = i, ClientName = "Name" + i });
        }
    }
}

static class Cache
{
    public static BlockingCollection<Client> bc = new BlockingCollection<Client>();


    public static void Consume()
    {
        foreach (var item in bc.GetConsumingEnumerable())
        {
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " - " + item + " - " + DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss.fff tt"));
        }
    }
}

public class Client
{
    public int ClientId { get; set; }
    public string ClientName { get; set; }
}
}

提前致谢

【问题讨论】:

    标签: c# multithreading thread-safety consumer blockingcollection


    【解决方案1】:

    一旦你消费了一个元素,它就会从集合中移除,因此没有其他线程能够访问它(至少通过集合)。

    那个 Cache 对我来说更像是一个缓冲区。无论如何,它在阻塞集合之上添加了什么?缓存能够使用自己的元素,这很奇怪。

    【讨论】:

    • 谢谢。你说的对。它是一个缓冲区。名字无关紧要。我想问的场景是,当线程 1 正在消费时,是否有机会在执行该线程 2 时并行消费并更改线程 1 中使用的项目的值,因为如您所见,我调用 Consumer 三次并行(Button1_Click 事件)
    • 那么答案是否定的,没有机会,而是因为不同的线程不能消耗相同的元素。您是否需要不同的线程来访问集合中的所有元素?如果是这种情况,您不能使用 GetConsumingEnumerable() 方法。
    • 没有。我想要的是让多个消费者尽快使用缓冲区。那么在线程 1 上的 foreach 循环中对“item”对象进行的任何操作都不会被线程 2 修改?因为你可以看到 Consume 方法是静态的。
    • 它不会被修改,因为如果它已经为线程2返回它,消费枚举将不会为线程1返回它。每个线程将获得一些项目,但不会有重叠.
    • 看来你是对的。每个线程都在访问自己的项目“实例”
    【解决方案2】:

    BlockingCollection 仅阻止集合本身。不是列表中的对象。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-18
      • 1970-01-01
      • 1970-01-01
      • 2011-06-04
      相关资源
      最近更新 更多