在Javascript中创建数百万个对象

j2cgzkjk  于 2023-05-27  发布在  Java
关注(0)|答案(2)|浏览(215)

让我第一个说,这不是我通常做的事情,但出于好奇,我会看看是否有人有一个好主意,如何处理这样的问题。
我正在开发的应用程序是一个模拟的游戏Let's make a Deal的例子,其中包含Monty Hall问题。
我不会详细介绍我的实现,但它或多或少允许用户输入他们想要模拟的游戏数量,然后如果一个选项被关闭,这些游戏的玩家不会切换他们的选择,而如果它被打开,他们将切换他们的选择游戏的每一个示例。
我的对象生成器看起来像这样:

const game = function(){
    this[0] = null;
    this[1] = null;
    this[2] = null;
    this.pick = Math.floor(Math.random() * 3);
    this.correctpick = Math.floor(Math.random() * 3);
    this[this.correctpick] = 1;
    for (let i=0; i<3; i++){
        if ((this[i] !== 1) && (i !== this.pick)){
            this.eliminated = i;
            break;
        }
    }
}

const games = arg => {
    let ret = [];
    for(let i=0; i<arg; i++){
        ret.push(new game);
    }
    return ret;
}

这个结构生成一个数组,我稍后将其字符串化,看起来像这样:

[
  {
    "0": 1,
    "1": null,
    "2": null,
    "pick": 2,
    "correctpick": 0,
    "eliminated": 1
  },
  {
    "0": null,
    "1": null,
    "2": 1,
    "pick": 2,
    "correctpick": 2,
    "eliminated": 0
  }
]

尽管游戏的构造函数看起来很草率,但原因是我已经将其重构为具有尽可能少的函数调用,现在我实际上只在当前时间调用Math函数(我删除了任何帮助函数,使代码更容易阅读,以选择性能)。
这个应用程序可以在浏览器和节点(跨平台)中运行,但我已经将用户可以传递到游戏功能中的参数限制为500万。超过这个时间,进程(或窗口)将冻结超过几秒钟,甚至可能崩溃。
如果用户给出了一个很大的数字,我还能做些什么来提高性能呢?如果你需要更多的信息,我很乐意提供!
谢谢!

g0czyy6m

g0czyy6m1#

明显的性能优化是根本不创建和存储500万个对象,从而缓解内存压力。相反,你只在需要的时候动态地创建对象,然后立即丢弃它们。我不确定你的应用程序是做什么的,但听起来你想在使用不同选项评估结果时重用相同的游戏示例。在这种情况下,你当然需要存储它们-但我建议重新考虑设计,并考虑立即评估每个游戏的所有可能的选项,只积累每个选项的结果,但不保留所有游戏的内存。
除此之外,我建议简化一点:

  • 您可以完全放弃该循环,并使用一些巧妙的算法来找到被删除的选项:this.eliminated = this.pick == this.correctpick ? +!this.pick : 3 - this.pick - this.correctpick;。或者使用一个简单的查找表this.eliminated = [1, 2, 1, 2, 0, 0, 1, 0, 0][this.pick * 3 + this.correctpick]
  • 我会避免将数组元素的类型从null(引用)更改为1(数字)。只要将它们保持为整数,并使用0初始化元素即可。
  • 不要在对象中存储6个完全冗余的属性。你只需要其中的两个:pickcorrectpick-当你需要的时候,其他的一切都可以在运行中计算出来。只有在计算量很大并且结果经常使用的情况下,预计算和存储它才是有利的。这两种情况都不是,但是保持低内存占用是很重要的(但是,不要期望太多)。
44u64gxh

44u64gxh2#

不确定您的实现,但您真的需要Array吗?
如何只使用结果(见片段)?
如果它阻止了你担心的浏览器,也许将工作委托给web worker是解决方案:请参阅this jsFiddle以获取此片段的Web Worker版本。

(() => {
  document.querySelector("#doit")
    .addEventListener("click", playMontyHall().handleRequest);

  function playMontyHall() {
    const result = document.querySelector("#result");
    const timing = document.querySelector("#timing");
    const nOfGames = document.querySelector("#nGames");
    const switchDoors = document.querySelector("#switchyn");

    // Create a game
    const game = (doSwitch) => {
      const doors = [0, 1, 2];
      const pick = Math.floor(Math.random() * 3);
      const correctPick = Math.floor(Math.random() * 3);
      const eliminated = doors.filter(v => v !== pick && v !== correctPick)[0];

      return {
        correctpick: correctPick,
        pick: doSwitch ? doors.filter(v => v !== pick && v !== eliminated)[0] : pick,
        eliminated: eliminated,
      };
    };
    
    const getWinner = game  => ~~(game.correctpick === game.pick);
    
    // Sum  wins using a generator function
    const winningGenerator = function* (doSwitch, n) {
      let wins = 0;
      
      while (n--) {
        wins += getWinner(game(doSwitch));
        yield wins;
      }
    };

    // calculate the number of succeeded games
    const calculateGames = (nGames, switchAlways) => {
      const funNGames = winningGenerator(switchAlways, nGames);
      let numberOfWins = 0;
      
      while (nGames--) {
        numberOfWins = funNGames.next().value;
      }
      
      return numberOfWins;
    }
    
    const cleanUp = playOut => {
        result.textContent =
        "Playing ... (it may last a few seconds)";
      timing.textContent = "";
      setTimeout(playOut, 0);
    };
    
    const report = results => {
        timing.textContent = `This took ${
         (performance.now() - results.startTime).toFixed(3)} milliseconds`;
      result.innerHTML =
         `<b>${!results.switchAlways ? "Never s" : "Always s"}witching doors</b>:
         ${results.winners} winners out of ${results.nGames} games
         (${((results.winners/+results.nGames)*100).toFixed(2)}%)`;
    };
    
    // (public) handle button click
    function clickHandle() {
     
      cleanUp(() => {
        const nGames = nOfGames.value || 5000000;
        const switchAlways = switchDoors.checked;
        report({
          switchAlways: switchAlways,
            startTime: performance.now(),
          winners: calculateGames(nGames, switchAlways),
          nGames: nGames
        });
      });
      
    }

    return {
      handleRequest: clickHandle
    };
  }

})();
body {
  margin: 2em;
  font: normal 12px/15px verdana, arial;
}

#timing {
  color: red;
}
<p><input type="number" id="nGames" value="5000000"> N of games</p>
<p><input type="checkbox" id="switchyn"> Always switch doors</p>
<p><button id="doit">Play</button>
<p id="result"></p>
<p id="timing"></p>

相关问题