0

我尝试使用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%。

4

1 回答 1

2

这是 GC 抖动的常见症状。在不了解更多关于您在 Expand 方法中所做的事情的情况下,我最好的猜测是这将是您的根本原因。某些共享数据访问也可能是罪魁祸首,要么通过调用远程系统,要么通过锁定对共享资源的访问。

在你做任何事情之前,你需要使用探查器或其他工具来确定确切的原因。不要猜测,因为这只会浪费您的时间,也不要在这里等待答案,因为没有完整的程序是无法回答的。正如您从实验中已经知道的那样,没有任何东西Parallel.ForEach会导致这种情况。

于 2012-12-20T18:56:28.943 回答