用java写了一个游戏计算最高得分的工具,游戏规则是,一个厨师能够带一个厨具,做三种菜谱,而后能够上场三个厨师。厨师和厨具别离有技能,技能有许多种成果,有些非凡的还能影响其余厨师,菜谱有技法要求限度。计算就是用3个厨师,3个厨具,9个菜谱,计算得分。
厨师有60多个,菜谱200多,厨具几十个。
首先想到了动静布局,然而每个菜谱须要耗费肯定数量食材,每种食材都有数量限度,前一个菜谱的抉择会影响后边的后果,厨师,厨具,菜谱能够做的数量,维度太多,搜寻空间太大,没想出思路。
最初想到的思路是,生成 9个菜谱的有序组合(安菜谱价格由高到低,生成),3个厨师的无序组合,三个厨具的有序组合。
菜谱组合数41989
厨师组合数3095
厨具组合数79079
而后先组合厨师和菜谱,保留得分最高的3k个,而后再组合厨具,从新计算得分。我只应用前1000个菜谱组合,在应用i7-6700HK的cpu上计算工夫也要十几分钟。
最开始认为是算法写的烂,三个维度数据量太大。而后理解到idea的profiler工具能够用于性能剖析。
剖析后果后果如图
能够从图中看到,对一些函数的cpu应用状况有一个统计,左侧是函数的cpu应用占比。然而统计的不全,应该是一些非函数调用的语句没有统计。
最开始一个线程,30个厨师组合,1000个有序菜谱组合,一次计算耗时是50s左右,应用profiler剖析cpu耗时,发现是计算厨师技能的函数耗时占比30%
这个函数是计算三个厨师的技法加成,以及技法对其余厨师的影响,大量的加法运算,导致耗时长。其实这个函数只和厨师组合无关,所以厨师组合确定,技法成果也应该确定了,然而我的每一组厨师和每一组菜谱(有序组合变无序为1680个)的搭配都要调用该办法,也就是反复计算了1680次。在没应用profiler前,还真不知道大部分耗时在这里。
优化后耗时变为30s,
而后持续测试, 发现这次ArrayList的subList办法和get办法耗时占大头,
因为我将长度为9的菜谱组合放在ArrayList中,当初要拆成3个3等分,所以应用了subList,最初改为应用二维数组装三等分的菜谱。
优化后耗时变为21s左右。
说到这里有个很神奇的景象,我的性能测试在 window10下, 别离应用openjdk8,oraclejdk11,oraclejdk15,GraalVM CE 20.2.0,下测试, 除了GraalVM CE 20.2.0,其余的都稳固在20s左右,唯独GraalVM,最初能优化到14s左右,而我发现这个优化会和一个for循环无关,
14秒耗时版本
20秒耗时版本
不出意外,我不懂汇编,没有自卑到剖析汇编后的代码,然而感觉和Link无关,于是把关涉大量计算局部的LinK都改为了对象数组。
后果执行工夫缩小到7s左右。 当我兴奋的应用openjdk8,oraclejdk11,oraclejdk15测试的时候,发现没有变动,还是20秒左右,只有GraalVM稳固在7秒。
mmp...