减少这个JS程序的资源占用?
Reduce resource usage of this JS program?
我写了下面的 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
设置为非常大的数字(例如一百万)时,它开始变慢并最终阻塞。作为参考,这是将生成并添加到数组中的对象的数量 - 正如您可能在代码中看到的那样,该数组循环了很多次。但即使有 100 万个对象,每个对象最多也只有 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));
(See this link 有关该评论的信息。)
我写了下面的 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
设置为非常大的数字(例如一百万)时,它开始变慢并最终阻塞。作为参考,这是将生成并添加到数组中的对象的数量 - 正如您可能在代码中看到的那样,该数组循环了很多次。但即使有 100 万个对象,每个对象最多也只有 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));
(See this link 有关该评论的信息。)