我已经看过很多关于如何在生产者 - 消费者场景中使用BlockingCollection<T>
的例子,甚至是如何一次消费一个元素here。我对并行编程很新,所以我面临以下问题:
问题确实是如何在下面的示例中编写方法ConsumerProducerExample.ConsumerMethod
,以便它为数组中的每个元素消耗double
的前2 BlockingCollection<Double>
,然后继续为数组中的每个元素使用下一个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)
表示)。
答案 0 :(得分: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();
}
}
}