0

我已经看到很多关于如何BlockingCollection<T>在生产者-消费者场景中使用 a 的示例,甚至是如何在此处一次使用一个元素。我对并行编程很陌生,所以我面临以下问题:

实际上,问题在于如何编写ConsumerProducerExample.ConsumerMethod下面示例中的方法,以便它为数组中的每个元素消耗前 2doubleBlockingCollection<Double>,然后为数组中的每个元素消耗下一个 2 double,依此类推。

我已经在下面的示例中编写了该方法,但这不是我希望它工作的方式。这是我在上面链接的示例中所知道的。恰恰相反:就像这里一样,它会double在跳转到BlockingCollection<Double>数组的下一个之前消耗掉每个。而且,我希望它只消耗两个double,然后跳转到下一个BlockingCollection<Double>,消耗两个double,等等。完成数组循环后,它应该再次double为每个BlockingCollection<Double>元素消耗下两个,依此类推。

public class ConsumerProducerExample
{
    public static BlockingCollection<Double>[] data;
    public static Int32 nEl = 100;
    public static Int32 tTotal = 1000;
    public static Int32 peakCounter = 0;

    public static void InitData()
    {
        data = new BlockingCollection<Double>[nEl];
        for (int i = 0; i < nEl; i++) data[i] = new BlockingCollection<Double>();
    }

    public static void ProducerMethod()
    {
        Int32 t = 0, j;
        while (t < ConsumerProducerExample.tTotal)
        {
            j = 0;
            while (j < ConsumerProducerExample.nEl)
            {
                data[j].Add(Math.Sin((Double)t / 10.0D));
                j++;
            }
            t++;
        }
        j = 0;
        while (j < ConsumerProducerExample.nEl)
        {
            data[j].CompleteAdding();
            j++;
        }
    }

    public static void ConsumerMethod()
    {
        // THE PROBLEM IS WITH THIS METHOD

        Double x1, x2;
        Int32 j = 0;
        while (j < Program.nEl)
        {
            while (!data[j].IsCompleted)
            {
                try
                {
                    x1 = data[j].Take();
                    x2 = data[j].Take();
                }
                catch (InvalidOperationException)
                {
                    break;
                }

                if (x1 * x2 < 0.0)
                {
                    Program.peakCounter++;
                }
            }

            j++;
        }
    }
}

它们应该像这样使用:

ConsumerProducerExample.InitData();
Task task1 = Task.Factory.StartNew(ConsumerProducerExample.ProducerMethod);
Task task2 = Task.Factory.StartNew(ConsumerProducerExample.ConsumerMethod);

有什么建议么?

简而言之,这是一种尝试同时计算nEl微分方程解中的峰值(sin(x)在本例中,解由 表示)。

4

1 回答 1

2

基本上,您需要摆脱内部循环并添加另一个外部循环,该循环遍历所有集合,直到它们完成。就像是:

while (!data.All(d => d.IsCompleted))
{
    foreach (var d in data)
    {
        // only takes elements from the collection if it has more than 2 elements
        if (d.Count >= 2)
        {
            double x1, x2;
            if (d.TryTake(out x1) && d.TryTake(out x2))
            {
                if (x1 * x2 < 0.0)
                    peakCounter++;
            }
            else
                throw new InvalidOperationException();
        }
    }
}
于 2012-10-21T10:47:37.580 回答