【问题标题】:Creating millions of Objects in Javascript在 Javascript 中创建数百万个对象
【发布时间】:2018-07-07 04:46:00
【问题描述】:

让我先说这不是我通常会做的事情,但出于好奇,我会看看是否有人对如何处理此类问题有好的想法。

我正在开发的应用程序是游戏Let's make a Deal 的模拟示例,其中包含蒙蒂霍尔问题。

我不会详细介绍我的实现,但它或多或少允许用户输入他们想要模拟的游戏数量,然后如果关闭某个选项,那么这些 x 游戏的玩家不会切换他们的选择,而如果打开它,他们会在游戏的每个实例中切换他们的选择。

我的对象生成器如下所示:

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
  }
]

游戏的构造函数看起来很草率,原因是我已经将它重构为尽可能少的函数调用,现在我实际上只在当前时间调用数学函数(我删除了任何帮助函数使代码更易于阅读,以提高性能)。

这个应用程序可以在浏览器和节点(跨平台)中运行,但我已将用户可以传递到游戏功能的 arg 限制为 500 万。超过这个时间,进程(或窗口)就会冻结超过几秒钟,甚至可能崩溃。

如果用户提供大量数据,我还能做些什么来提高性能?另外,如果您需要更多信息,我很乐意提供!

谢谢!

【问题讨论】:

  • 是否有可能将它们的属性粉碎到不同的数组/映射中?
  • 如果您不使用符合 JSON 的字符串,请不要使用术语 JSON
  • “这个结构会生成一些 json 数据......” 扩展 Nina 的评论:不,它没有。它生成一些 JavaScript 对象。 JSON 是一种用于数据交换的文本表示法(More here.) 如果您正在处理 JavaScript 源代码,而不是处理 字符串,那么您就不是在处理 JSON。
  • 抱歉,稍后在我的代码中我使用 JSON.stringify(simulation),其中模拟是您在上面看到的数据结构。
  • @simon 为什么不i 那么???

标签: javascript object


【解决方案1】:

不确定你的实现,但你真的需要Array吗?

只使用结果如何(见 sn-p)?

如果它阻止了您担心的浏览器,也许将工作委托给web worker 是解决方案:请参阅this jsFiddle 了解此 sn-p 的网络工作者版本。

(() => {
  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>

【讨论】:

  • 这是一个了不起的解决方案!我会看看你的代码谢​​谢!
  • 我把答案改成了你的。 Kooilnc 这里有一些令人难以置信的东西,谢谢!
  • 好吧,你让我迷上了网络/服务工作者。太感谢了。我只有一个简单的问题要问你。你的 setTimeout(playout, 0) 在 cleanup() 有什么意义?我在您的代码中唯一不完全理解的事情。再次感谢您! :)
  • 嗨@simon,很高兴我能帮上忙。 setTimeout 的重点是能够清理屏幕。没有它,UI 会在播放完成后 重写。这有点诡计。
  • 附录:setTimeout 在 web worker 代码中不是必需的:您可以使用 worker 消息处理程序来清理屏幕(因为 worker 是不同的线程)。我调整了jsfiddle代码。
【解决方案2】:

明显的性能优化是根本不创建和存储 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 个完全冗余的属性。您只需要其中的 2 个:pickcorrectpick - 其他所有内容都可以在您需要时动态计算。仅当计算量大且结果经常使用时,预先计算和存储它才是有利的。这两种情况都不是,但保持低内存占用很重要(不过,不要对此抱有太大期望)。

【讨论】:

  • 感谢您的帮助。我尝试更改为您推荐的第一行,但它破坏了 sim。它不是在做同样的事情。但是,如果这会提高性能,我将使用您的想法将数值设置为默认值 0。
  • 糟糕,我错过了pick 可能是正确的,它有点复杂(但仍然不需要循环)。但是,Monty Hall 的规则不是说如果选择正确,必须随机选择被淘汰的选项吗?您总是在消除两个可用选项中的第一个。
  • 我正在消除循环发现的第一个未被选中且不包含奖品的人。这就是 if 条件 if ((this[i] !== 1) && (this.pick !== i)){
  • @simon 是的,我认为“第一个”是错误的。您需要选择一个满足条件的随机值(可能有 1 或 2 个值可以消除)。
  • 好吧,我唯一需要重新随机删除房间的情况是,如果用户正确选择了第一选择,这种情况几乎不会发生(33% 的时间)。这是一个有趣的项目,我一直持怀疑态度,直到我第一次看到我的代码在 100 多场比赛中运行,如果你切换,你的几率会上升到 66% :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-02-04
  • 1970-01-01
  • 2011-08-15
  • 1970-01-01
  • 2021-07-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多