【发布时间】:2021-10-19 15:53:31
【问题描述】:
我正在努力使用Parallel.For 循环。我可以说他们确实加快了我长时间运行的代码,但我得到了空对象错误,就好像代码在完成并行循环之前移动了一样。下面是我尝试过的带有注释掉的 Parallel.For 语句的代码。
public bool Calculate()
{
// make list of all possible flops 22100
List<Flop> flops = new List<Flop>();
CardSet deck = new CardSet();
for (int i = 0; i < deck.Size() - 2; i++)
{
SbCard card1 = deck.GetCard(i);
for (int j = i + 1; j < deck.Size() - 1; j++)
{
SbCard card2 = deck.GetCard(j);
for (int k = j + 1; k < deck.Size(); k++)
{
SbCard card3 = deck.GetCard(k);
flops.Add(new Flop(card1, card2, card3));
}
}
}
int progress = 0;
var watch = System.Diagnostics.Stopwatch.StartNew();
// Loop over each flop
//Parallel.For(0, flops.Count, i =>
for (int i = 0; i < flops.Count; i++)
{
Dictionary<FlopEquityHoldemHandPair, FlopEquityHoldemHandPair> flopPairs =
new Dictionary<FlopEquityHoldemHandPair, FlopEquityHoldemHandPair>();
Flop flop = flops[i];
String filePath = Directory.GetCurrentDirectory() + "\\flops\\" +
flop.GetSorted() + ".txt";
if (!File.Exists(filePath))
{
// make list of all available starting hands
List<HoldemHand> hands = new List<HoldemHand>();
deck = new CardSet();
deck.RemoveAll(flop);
for (int j = 0; j < deck.Size() - 1; j++)
{
SbCard card1 = deck.GetCard(j);
for (int k = j + 1; k < deck.Size(); k++)
{
SbCard card2 = deck.GetCard(k);
hands.Add(new HoldemHand(card1, card2));
}
}
// loop over all hand vs hand combos
//Parallel.For(0, hands.Count - 1, j =>
for (int j = 0; j < hands.Count - 1; j++)
{
HoldemHand hand1 = hands[j];
//Parallel.For(j + 1, hands.Count, k =>
for (int k = j + 1; k < hands.Count; k++)
{
HoldemHand hand2 = hands[k];
if (!hand1.Contains(hand2))
{
FlopEquityHoldemHandPair holdemHandPair = new
FlopEquityHoldemHandPair(hand1, hand2);
if (!flopPairs.ContainsKey(holdemHandPair))
{
// next line triggers a loop of 1980 iterations
flopPairs.Add(holdemHandPair, new
FlopEquityHoldemHandPair(new
EquityHoldemHand(hand1), new
EquityHoldemHand(hand2), flop));
}
}
}//);
}//);
// WRITE FILE FOR CURRENT FLOP
StringBuilder sb = new StringBuilder();
foreach (FlopEquityHoldemHandPair pair in flopPairs.Values)
{
// Null value appears in flopPairs.Values and the list of values is around 200 short of the 600k values it should have
sb.AppendLine(pair.ToString());
}
File.WriteAllText(filePath, sb.ToString());
// reports calculation progress 1% at a time
int num = ((int)(i * 100 / 22100));
if (num > progress)
{
progress = num;
Console.WriteLine("Progress: " + progress + "%");
}
}
}//);
watch.Stop();
var elapsedMs = watch.ElapsedMilliseconds;
Console.WriteLine("Finished in " + elapsedMs / 60000 + "mins");
return true;
}
当我在这段代码的后期到达foreach 循环时,flopPairs 中有一些项目。值为 null 并且字典没有应有的那么大 - 就好像在代码继续之前某些计算没有完成一样。我很抱歉,如果没有更多代码,这段代码就无法运行,但有很多东西可以提供。如果问题对某人来说不是很明显,我可以尝试提供一个最小的简化示例。
【问题讨论】:
-
根据这个答案(stackoverflow.com/questions/10153729/…)paralell foreach 应该阻塞,直到循环的最后一部分完成。 |请在注释中指定您获得 Null 值的行。
-
它是 Parallel For 而不是 Parallel Foreach。不确定这是否会有所作为。我在出现空值的代码中添加了注释
-
我有两个建议给你。一是避免嵌套
Parallel循环。对于大多数工作负载来说,一个Parallel循环就足够了。将一个嵌套在另一个中只会增加开销。另一个建议是在尝试编写多线程程序之前系统地研究线程。您必须熟悉线程同步、竞争条件、内存屏障等概念。要学习的东西很多,仅凭直觉和完全缺乏是不可能成功的。这是一个有价值的在线资源:Threading in C#,作者 Joseph Albahari。 -
Dictionary不是线程安全的,因此时髦的数据不足为奇。考虑使用线程安全集合,如ConcurrentDictionary。 -
@JohnWu 谢谢 - 这似乎解决了我的问题。不知道字典是导致问题的原因
标签: c# multithreading for-loop parallel-processing parallel.for