代码似乎在 Parallel.For 循环完成之前继续进行
Code seems to move on prior to Parallel.For loops finishing
我正在努力使用 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 并且字典没有应有的那么大 - 好像在代码继续之前某些计算没有完成。很抱歉,如果没有更多代码,这段代码将无法运行,但可以提供很多。如果问题对某些人来说不是很明显,我可以尝试提供一个最小的简化示例。
正如 John Wu 在评论中所说,Dictionary 不是线程安全的,这导致了我的问题。使用 ConcurrentDictionary 是正确答案
我正在努力使用 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 并且字典没有应有的那么大 - 好像在代码继续之前某些计算没有完成。很抱歉,如果没有更多代码,这段代码将无法运行,但可以提供很多。如果问题对某些人来说不是很明显,我可以尝试提供一个最小的简化示例。
正如 John Wu 在评论中所说,Dictionary 不是线程安全的,这导致了我的问题。使用 ConcurrentDictionary 是正确答案