很难解释这一点。我花了三天才弄明白。
我正在制作一个序列化库,而我正试图让它变速。它只是将对象序列化为缓冲区。
我注意到如果我先运行我的基准测试,那么编码需要大约500毫秒。但是,如果我先运行我的测试套件,那么之后我的基准测试需要大约1300毫秒来编码。
这非常奇怪,因为他们使用两个完全不同的对象进行操作,根本没有任何共享。
我完成了我的程序并开始对每一行进行基准测试,直到我最终找到了占800毫秒差异的行。
这是函数中的这一行:for (var j = arrLen; j < refLen; j++) {
也不是循环的主体。只是for循环的标题。
我不知道如何修复它。除了最近只是一时兴起我试图复制该功能(只是复制和粘贴)并重命名它在名称的末尾包含一个0。
然后我让我的测试套件调用第一个函数,我的基准测试调用第二个函数。时差消失了。功能内容和参数列表完全相同。
我的主要理论是:第一次调用此函数时,函数已经过优化,我想循环已展开。这就是为什么首先调用基准测试没有问题:因为第一次调用它时它会被优化。但是,如果稍后调用它,它不会针对给定的输入进行优化,因此运行速度非常慢。
我的问题是:只是复制和粘贴此功能数千次并且每个编码使用此功能的不同版本,有没有办法解决此问题以消除时间区别? 500毫秒到1300毫秒之间的差异很大。
我一直试图对此进行测试,但这非常困难,因为这个错误是如此模糊。希望我的文字描述足够了。
编辑:这是被调用的函数。
function endEncodeArray(ref, arrLen, writeRepeatFunction, wBuffer) {
var refLen = ref.length;
if (refLen - arrLen > 0) {
for (var j = arrLen; j < refLen; j++) { // <-- this line slow
writeRepeatFunction(ref[j], wBuffer);
}
}
}
编辑2:手动将函数写为字符串,评估它,然后调用它的方法似乎可以解决性能问题。由于我无法弄清楚如何隔离测试用例,我想我只是将其用作绷带修复。
答案 0 :(得分:0)
您可能会面临deopt,因为您提到的基准测试和测试使用两个完全不同的对象。有关详细信息,请参阅http://mrale.ph/blog/2015/01/11/whats-up-with-monomorphism.html,希望有所帮助。