我编写了以下JS程序,我使用node从命令行运行该程序。
//step one: create an array of remaining creatures
var remainingCreatures = [];
//some config variables:
var amt = 1000; //amount of creatues generated
var maxhlt = 1000; //max value for creature health stat
var minhlt = 100; //min value for creature health stat
var maxatk = 100; //max value for creature attack stat
var minatk = 1; //min value for creature attack stat
function remove(target) { //helper function to easily remove creatues from the array
var index = remainingCreatures.indexOf(target);
if (index > -1) {
remainingCreatures.splice(index, 1);
}
}
//generate creatures
//each creature has an Attack, Health, and Aggressiveness , as well as Instabillity, the average of the three
//A creature's Instabillity is added to the attack points of its opponent in fights.
for (var i = 0; i < amt; i++) {
var atkVal = Math.floor((Math.random() * maxatk) + minatk);
var hltVal = Math.floor((Math.random() * maxhlt) + minhlt);
var insVal = (atkVal + hltVal) / 2;
remainingCreatures[i] = {num: i, atk: atkVal, hlt: hltVal, ins: insVal, fts: 0, ihlt: hltVal};
}
console.log(amt + " creatues generated, starting melee...");
function fight(cr1, cr2) { //function to handle fighting, randomly creates creature pairs and has them fight
function attack(a, b) {
console.log("[ROUND 1] Creature 1 (#" + a.num + ") is attacking first.");
b.hlt = b.hlt - (a.atk + b.ins);
console.log("[HIT] Creature #" + b.num + " health reduced to " + b.hlt);
if (b.hlt <= 0) {
console.log("[DEATH] Creature #" + b.num + " Eliminated");
remove(b);
} else {
console.log("[ROUND 2] Creature 2 (#" + b.num + ") is attacking second.");
a.hlt = a.hlt - (b.atk + a.ins);
console.log("[HIT] Creature #" + a.num + " health reduced to " + a.hlt);
if (a.hlt <= 0) {
console.log("[DEATH] Creature #" + a.num + " Eliminated");
remove(a);
}
}
}
console.log("[FIGHT] Pair generated: Creature #" + cr1.num + " and Creature #" + cr2.num);
cr1.fts++;
cr2.fts++;
if (cr1.ins <= cr2.ins) {
attack(cr1, cr2);
} else {
attack(cr2, cr1);
}
}
for(;true;) {
if(remainingCreatures.length == 1) break;
fight(remainingCreatures[Math.floor(Math.random() * remainingCreatures.length)], remainingCreatures[Math.floor(Math.random() * remainingCreatures.length)]);
}
console.log(" ");
console.log("[WIN] Creature #" + remainingCreatures[0].num + " has won!");
console.log("Starting array size was " + amt + " creatures")
console.log(remainingCreatures[0]);
出于某种原因,当amt
设置为非常大的数字(例如一百万(时,这开始减慢并最终窒息。作为参考,这是将生成并添加到数组中的对象数量 - 正如您可能在代码中看到的那样,该数组被循环了很多。但即使有一百万个对象,每个对象最多也只有大约 80 个字节。该程序正在执行的计算非常基本。
所以我的问题是:为什么运行这个程序如此耗费资源,我怎样才能在不彻底改变程序功能的情况下修复或缓解它?
首先,无论多小,一百万个东西都会对性能产生影响。 另一个问题是你的设计本质上是低效的。
查看您的remove()
函数。它首先找到元素的索引,然后将其删除。如果该数组中有一百万个元素,平均而言,它需要将传递的值与500,000 个元素进行比较,以便在删除之前找到它。有一种简单的方法可以解决这个问题;直接传递索引,而不是使用.indexOf
。
function fight(ind1, ind2) { //function to handle fighting, randomly creates creature pairs and has them fight
var cr1 = remainingCreatures[ind1];
var cr2 = remainingCreatures[ind2];
function attack(a, b) {
console.log("[ROUND 1] Creature 1 (#" + a.num + ") is attacking first.");
b.hlt = b.hlt - (a.atk + b.ins);
console.log("[HIT] Creature #" + b.num + " health reduced to " + b.hlt);
if (b.hlt <= 0) {
console.log("[DEATH] Creature #" + b.num + " Eliminated");
remove(ind2);
} else {
console.log("[ROUND 2] Creature 2 (#" + b.num + ") is attacking second.");
a.hlt = a.hlt - (b.atk + a.ins);
console.log("[HIT] Creature #" + a.num + " health reduced to " + a.hlt);
if (a.hlt <= 0) {
console.log("[DEATH] Creature #" + a.num + " Eliminated");
remove(ind1);
}
}
}
console.log("[FIGHT] Pair generated: Creature #" + cr1.num + " and Creature #" + cr2.num);
cr1.fts++;
cr2.fts++;
if (cr1.ins <= cr2.ins) {
attack(cr1, cr2);
} else {
attack(cr2, cr1);
}
}
for(;true;) {
if(remainingCreatures.length == 1) break;
fight(Math.floor(Math.random() * remainingCreatures.length), Math.floor(Math.random() * remainingCreatures.length));
}
没有太多其他方法可以轻松提高性能,但仅此一项就足够了。但是,为了使您的代码更具可读性,请考虑替换它:
for(;true;) {
if(remainingCreatures.length == 1) break;
fight(Math.floor(Math.random() * remainingCreatures.length), Math.floor(Math.random() * remainingCreatures.length));
}
有了这个:
// Consider using === and !== as best practice, but not necessary here
while (remainingCreatures.length != 1)
fight(Math.floor(Math.random() * remainingCreatures.length), Math.floor(Math.random() * remainingCreatures.length));
(有关该评论的信息,请参阅此链接。