我尝试使用Parallel.Foreach
实现以下算法。我认为并行是微不足道的,因为它没有同步问题。它基本上是一个蒙特卡罗树搜索,我在那里探索并行的每个孩子。蒙特卡洛的东西并不是很重要,你必须要知道的是我有一个方法可以运行一些树,并且我在根孩子身上用Parallel.Foreach
调用它。以下是进行并行调用的片段。
public void ExpandParallel(int time, Func<TGame, TGame> gameFactory)
{
int start = Environment.TickCount;
// Creating all of root's children
while (root.AvailablePlays.Count > 0)
Expand(root, gameInstance);
// Create the children games
var games = root.Children.Select(c =>
{
var g = gameFactory(gameInstance);
c.Play.Apply(g.Board);
return g;
}).ToArray();
// Create a task to expand each child
Parallel.ForEach(root.Children, (tree, state, i) =>
{
var game = games[i];
// Make sure we don't waste time
while (Environment.TickCount - start < time && !tree.Completed)
Expand(tree, game);
});
// Update (reset) the root data
root.Wins = root.Children.Sum(c => c.Wins);
root.Plays = root.Children.Sum(c => c.Plays);
root.TotalPayoff = root.Children.Sum(c => c.TotalPayoff);
}
Func<TGame, TGame>
委托是一个克隆工厂,因此每个孩子都有自己的游戏状态克隆。如果需要,我可以解释Expand
方法的内部,但我可以保证它只访问当前子树和游戏实例的状态,并且在这些类型中没有static
个成员。我认为可能Environment.TickCount
正在进行争用,但我在EnvironmentTickCount
循环内调用Parallel.Foreach
进行了一项实验,并获得了近100%的处理器使用率。
我只能在Core i5上使用45%到50%。
答案 0 :(得分:2)
这是GC捶打的常见症状。如果不了解你在Expand方法中做了什么,我最好的猜测是这将是你的根本原因。一些共享数据访问也可能是罪魁祸首,无论是通过调用远程系统,还是通过锁定对共享资源的访问。
在您执行任何操作之前,您需要使用分析器或其他工具确定确切原因。不要猜测,因为这会浪费你的时间,不要在这里等待答案,因为没有你的完整程序,它无法回答。正如您从实验中已经知道的那样,Parallel.ForEach
中没有任何内容会导致这种情况。