我想我需要Parallel.For来加速这个窝......但是怎么样?

时间:2016-06-20 22:23:35

标签: c# .net parallel-processing nested-loops parallel.foreach

我正在构建一个循环播放棒球运动员列表的功能,以创建所有可能的阵容组合。

我有每个位置的球员名单。即,Pitcher,Catcher,1st-Base等......

挑战在于有数十亿种组合,因此这是一个缓慢的过程。我一直在阅读使用System.Threading并行执行循环,但我没有基本级别的经验,我可以找到的示例看起来更简单(通常演示一个嵌套循环),并且我无法理解如何将它应用于多个嵌套循环。

在最里面嵌套的循环中,我正在测试以查看阵容是否有效,方法是 validateAndAddToTopLineups ,它采用了阵容,一系列有效的阵容参考,以及其他2个参数是用于确定阵容是否有效的常数限制。

我应该以不同的方式处理此过程,还是有人可以帮我翻译它以使用Parallel.For方法?

以下是我的嵌套循环:

for (int p = 0; p < _myPitchers.Count; p++) //For each pitcher
    for (int c = 0; c < _myCatchers.Count; c++) //For each catcher
        for (int b1 = 0; b1 < _myBase1.Count; b1++) //For each 1st base player
            for (int b2 = 0; b2 < _myBase2.Count; b2++) //For each 2nd base player
                for (int b3 = 0; b3 < _myBase3.Count; b3++) //For each 3rd base player
                    for (int ss = 0; ss < _myShortStops.Count; ss++) //For each shortstop
                        for (int oF = 0; oF < OutfielderCombos.Count; oF++) //For each outfielder lineup combination
                        {
                             Lineup testLineup = new Lineup(); //create new lineup
                             testLineup.Pitcher1 = _myPitchers[p];                   //pitcher 1
                             //testLineup.Pitcher1 = _myPitchers[p2];                //pitcher 2
                             testLineup.Catcher = _myCatchers[c];                    //catcher
                             testLineup.Base1 = _myBase1[b1];                        //1st base
                             testLineup.Base2 = _myBase2[b2];                        //2nd base
                             testLineup.Base3 = _myBase3[b3];                        //3rd base
                             testLineup.Shortstop = _myShortStops[ss];               //short stop
                             testLineup.Outfield1 = OutfielderCombos[oF].Outfield1;  //outfielder 1
                             testLineup.Outfield2 = OutfielderCombos[oF].Outfield2;  //outfielder 2
                             testLineup.Outfield3 = OutfielderCombos[oF].Outfield3;  //outfielder 3
                              //determine if lineup is valid, and if so add it to List<Lineup> _ValidLineups
                             validateAndAddToTopLineups(testLineup, ref _ValidLineups, ref SalaryCap, ref SameTeamLimit);
                         }

3 个答案:

答案 0 :(得分:1)

你那里有笛卡尔积。这是一个巨大的,但这就是你的方式:

var enumerator =
    from p in _myPitchers
    from c in _myCatchers
    from b1 in _myBase1
    from b2 in _myBase2
    from b3 in _myBase3
    from ss in _myShortStops
    from of in OutfielderCombos
    select new Lineup
        {
            Pitcher1 = p,
            Catcher = c,
            Base1 = b1,
            Base2 = b2,
            Base3 = b3,
            Shortstop = ss,
            Outfield1 = of.Outfield1,
            Outfield2 = of.Outfield2,
            Outfield3 = of.Outfield3
        };

然后你可以并行枚举这些组合:

var result = enumerator.AsParallel().Where(l => IsValid(l)).ToArray();

您必须修改验证以提供布尔IsValid()方法,但这会并行遍历您的大集。

答案 1 :(得分:1)

BlockingCollection https://msdn.microsoft.com/en-us/library/dd997371(v=vs.110).aspx会帮助你吗?在循环外部创建集合和一组试图从集合中提取条目的任务。每个任务都应该等到任务可用,运行它,然后等待另一个任务。在您调用validateAndAddToTopLineups时,您将尝试添加任务。您将能够将任务添加到BlockingCollection限制。 https://msdn.microsoft.com/en-us/library/dd267312(v=vs.110).aspx。我希望你赢了。

答案 2 :(得分:0)

阻止集合和枚举器方法都很棒,这意味着我至少让它们起作用。

我无法将它们与我原来的单线程嵌套循环进行比较或基准测试,因为我已经意识到在这里有很多迭代要做的事情.yyyyyyyyyyyyyyyyyyy *(y)^ yy。我甚至在一个拥有8个内核的快速Azure虚拟机上尝试过它,它仍然是残酷的。

我计算了分配给Uint64的迭代次数,这个数字是不可理解的。 18,446,744,071,628,531,200或18个quintillion!比我想的原始数十亿略多。

感谢您的帮助和想法,阻止集合是neato,并且实现起来非常简单!

如果有人建议如何将我的问题削减到可管理的大小或以不同方式处理,请告诉我!

... ...更新 仅供参考:我能够通过线性优化算法解决这个问题。我用了 lpsolve,可用于任何编程IDE或语言。它在不到一秒的时间内找到了最佳解决方案!