JavaScript:更快的轮盘选择

时间:2018-08-02 16:20:48

标签: javascript optimization v8 micro-optimization

我正在实现一种选择算法,该算法根据与其score值成正比的概率来选择对象。这使得得分更高的对象更有可能被选择。

我的实现如下:

var pool = [];
for (var i = 0; i < 100; i++)
    pool.push({ Id: i, Score: Math.random() * 100 << 0 });

const NUM_RUNS = 100000;
var start = new Date();
for( var i = 0; i < NUM_RUNS; i++ )
  rouletteSelection(pool);
var end = new Date();

var runningTime = (end.getTime() - start.getTime()) / 1000;
var avgExecutionTime = ( runningTime / NUM_RUNS ) * Math.pow(10,9);
console.log('Running Time: ' + runningTime + ' seconds');
console.log('Avg. Execution Time: ' + avgExecutionTime + ' nanoseconds');


function rouletteSelection(pool) {
        // Sum all scores and normalize by shifting range to minimum of 0
        var sumScore = 0, lowestScore = 0;
        pool.forEach((obj) => {
            sumScore += obj.Score;
            if (obj.Score < lowestScore)
                lowestScore = obj.Score;
        })
        sumScore += Math.abs(lowestScore * pool.length);
    
        var rouletteSum = 0;
        var random = Math.random() * sumScore << 0;
        for (var i in pool) {
            rouletteSum += pool[i].Score + lowestScore;
            if (random < rouletteSum)
                return pool[i];
        }
    
        //Failsafe
        console.warn('Could not choose roulette winner, selecting random');
        return pool[Math.random() * pool.length];
};

运行时,性能还不错:在我的机器上,每次调用rouleteSelection()大约需要2500-3200纳秒。但是,在生产中使用该功能之前,我想对其进行优化,并尽可能减少开销,因为在极端情况下该功能可能被称为数千万次。

一个显而易见的优化是将所有内容合并到一个循环中,这样对象数组仅被迭代一次。问题是,为了使分数标准化(负分数变为0),我需要知道最低分数。

有人对如何解决这个问题有任何想法吗?

1 个答案:

答案 0 :(得分:0)

冒着明显的危险:只是不要在每次对rouletteSelection的调用中都进行规范化。构造pool后,只需执行一次。