首页 > 解决方案 > 将数据从一个线程传递到另一个线程(不断地)

问题描述

我有两个不断运行的线程:

  1. Producer - 每次迭代它都会生成值并将它们放入一个 int 数组中。该数组被传递给消费者线程。Producer 不会再次使用生成的值。

  2. 消费者 - 每次迭代它都会从接收到的数组中创建一个字符串并将结果打印到控制台。

生成的数组值有一个顺序。它在两个线程中应该是相同的。


public class Producer
{
    private int[] m_outputData;

    private Random m_numberGenerator = null;

    private Thread m_runner = null;

    private Consumer m_consumer = null;

    public Producer()
    {
        m_outputData = new int[10];

        m_numberGenerator = new Random();

        m_runner = new Thread(new ThreadStart(Run));
        m_runner.IsBackground = true;

        m_consumer = new Consumer();
    }

    public void Start()
    {
        m_consumer.Start();

        m_runner.Start();
    }

    private void Run()
    {
        while (true)
        {
            for (int i = 0; i < m_outputData.Length; i++)
            {
                m_outputData[i] = m_numberGenerator.Next(1, 100);
            }

            m_consumer.SetData(m_outputData);

            Thread.Sleep(100);
        }
    }
}

public class Consumer
{
    private int[] m_inputData;

    private Thread m_runner = null;

    private readonly object m_dataLock = new object();

    public Consumer()
    {
        m_inputData = new int[10];

        m_runner = new Thread(new ThreadStart(Run));
        m_runner.IsBackground = true;
    }
    public void Start()
    {
        m_runner.Start();
    }

    public void SetData(int[] arr)
    {
        lock (m_dataLock)
        {
            for (int i = 0; i < m_inputData.Length; i++)
            {
                m_inputData[i] = arr[i];
            }
        }
    }

    private void Run()
    {
        while (true)
        {
            string data = "";

            lock (m_dataLock)
            {
                for (int i = 0; i < m_inputData.Length; i++)
                {
                    data += m_inputData[i].ToString();
                    data += ",";
                }
            }

            Console.WriteLine(data);

            Thread.Sleep(100);
        }
    }
}

目前,我使用一个简单的循环来一一复制这些值。该循环由锁保护。我已经锁定了 Array.Copy 方法,但是,它在使用小数组(函数调用)时看起来更昂贵。

在我的线程之间传递数组(性能方面)的最佳方式是什么?

标签: c#.netmultithreading

解决方案


更新:使用 ConcurrentQueue 支持多个消费者

这是一个使用 Task.Run() 而不是线程的非常简单的生产者/消费者示例。

这里非常重要的一点是生产者和消费者的实现是完全解耦的。并使用 aConcurrentQueue在生产者和消费者之间共享信息。

private static void Producer(ConcurrentQueue<int[]> eventQueue, CancellationToken cancellationToken)
{
    Random m_numberGenerator = new Random();

    while (true)
    {
        cancellationToken.ThrowIfCancellationRequested();

        int[] m_outputData = new int[10];

        for (int i = 0; i < m_outputData.Length; i++)
        {
            m_outputData[i] = m_numberGenerator.Next(1, 100);
        }

        eventQueue.Enqueue(m_outputData);

        Thread.Sleep(m_numberGenerator.Next(100, 201));
    }
}

private static void Consumer(ConcurrentQueue<int[]> eventQueue, CancellationToken cancellationToken)
{
    while (true)
    {
        cancellationToken.ThrowIfCancellationRequested();

        int[] m_inputData;
        if (eventQueue.TryDequeue(out m_inputData))
        {
            Console.WriteLine(string.Join(" ", m_inputData));
        }
        else
        {
            Console.WriteLine("No new data is available.");
        }
        Thread.Sleep(100);
    }
}

static void Main(string[] args)
{
    ConcurrentQueue<int[]> eventQueue = new ConcurrentQueue<int[]>();

    CancellationTokenSource consumerTokenSource = new CancellationTokenSource();
    CancellationToken consumerCancellationToken = consumerTokenSource.Token;

    Task.Run(() => Consumer(eventQueue, consumerCancellationToken), consumerCancellationToken);

    CancellationTokenSource producerTokenSource = new CancellationTokenSource();
    CancellationToken producerCancellationToken = consumerTokenSource.Token;

    Task.Run(() => Producer(eventQueue, producerCancellationToken), producerCancellationToken);

    Console.WriteLine("Press any ket to exit.");

    Console.ReadLine();
}

输出:

No new data is available.
8 57 70 28 78 58 40 79 39 87
61 5 12 75 21 56 77 15 96 29
No new data is available.
33 89 26 11 51 72 28 41 78 84
No new data is available.
92 74 80 54 78 24 78 68 46 16
64 78 84 88 40 60 46 1 41 81
19 25 80 2 68 7 68 51 98 9
No new data is available.
67 13 38 95 66 78 54 36 29 82
No new data is available.
53 25 48 26 63 32 68 94 78 43
89 56 55 73 76 55 71 1 95 18
20 12 71 51 45 93 68 46 5 52
No new data is available.
45 72 56 54 42 44 36 83 5 31
54 24 82 40 92 2 98 64 29 87
81 6 37 54 13 87 74 26 32 39
No new data is available.
68 11 83 18 22 14 28 64 13 14
18 58 48 69 5 2 67 48 40 24
No new data is available.
89 91 51 18 87 32 48 9 78 98
92 55 71 57 75 79 85 37 64 74
No new data is available.
40 87 79 7 43 82 73 59 84 98
35 21 92 67 5 27 96 16 4 35
55 65 93 97 48 26 87 62 4 59
No new data is available.
47 51 63 39 81 88 66 36 20 15
No new data is available.
55 21 50 65 9 75 59 41 48 71
98 33 14 14 46 35 47 72 22 95
No new data is available.
75 74 42 4 66 45 8 50 67 15
89 10 72 48 82 17 12 4 62 12

推荐阅读