提问人:Jochen Kühner 提问时间:11/8/2023 最后编辑:Jason AllerJochen Kühner 更新时间:11/8/2023 访问量:62
在 JavaScript 中将 GUID 从字节数组反序列化为字符串的快速且内存高效的方法
fast and memory efficient way to deserialize a GUID from a byte array to a string in JavaScript
问:
目前我使用了以下代码:
getGuid(): string {
const guid = this.array[this.offset + 3].toString(16).padStart(2, '0') + this.array[this.offset + 2].toString(16).padStart(2, '0') + this.array[this.offset + 1].toString(16).padStart(2, '0') + this.array[this.offset + 0].toString(16).padStart(2, '0') + "-" +
this.array[this.offset + 5].toString(16).padStart(2, '0') + this.array[this.offset + 4].toString(16).padStart(2, '0') + "-" +
this.array[this.offset + 7].toString(16).padStart(2, '0') + this.array[this.offset + 6].toString(16).padStart(2, '0') + "-" +
this.array[this.offset + 8].toString(16).padStart(2, '0') + this.array[this.offset + 9].toString(16).padStart(2, '0') + "-" +
this.array[this.offset + 10].toString(16).padStart(2, '0') + this.array[this.offset + 11].toString(16).padStart(2, '0') + this.array[this.offset + 12].toString(16).padStart(2, '0') + this.array[this.offset + 13].toString(16).padStart(2, '0') + this.array[this.offset + 14].toString(16).padStart(2, '0') + this.array[this.offset + 15].toString(16).padStart(2, '0');
this.offset += 16;
return guid;
}
但我认为它的效率非常低,并且由于创建的所有字符串而产生许多 gc 开销。问题是,我每秒收到一千条消息,我需要将其转换为字符串。(它在浏览器中,而不是在节点应用程序中)
this.array 是一个 Uint8Array
答:
2赞
T.J. Crowder
11/8/2023
#1
一般来说,如果没有具体的可衡量问题,就很难提出可以解决该问题的解决方案。如果没有测量(理想情况下是真实世界的测量而不是合成基准),你就不知道你正在做的事情是改善还是让事情变得更糟。
也就是说,在此用例中跳出的一件事是,您正在为相同的 256 个输入值重复重新创建填充的十六进制字符串。鉴于您看到的卷,最好一次性构建这些字符串并重用它们。这会消耗少量静态内存来存储 256 个字符串,但避免了对每个输入 GUID 的重复和操作。toString
padStart
您可以做的第二件事是将重复的属性访问缓存到本地 .const
例:
// Build the strings once
const byteStrings = Array.from({ length: 256 }, (_, value) =>
value.toString(16).padStart(2, "0")
);
// Reuse them
class Something {
// ...
getGuid(): string {
const { array, offset } = this;
const guid =
byteStrings[array[offset + 3]] +
byteStrings[array[offset + 2]] +
byteStrings[array[offset + 1]] +
byteStrings[array[offset + 0]] +
"-" +
byteStrings[array[offset + 5]] +
byteStrings[array[offset + 4]] +
"-" +
byteStrings[array[offset + 7]] +
byteStrings[array[offset + 6]] +
"-" +
byteStrings[array[offset + 8]] +
byteStrings[array[offset + 9]] +
"-" +
byteStrings[array[offset + 10]] +
byteStrings[array[offset + 11]] +
byteStrings[array[offset + 12]] +
byteStrings[array[offset + 13]] +
byteStrings[array[offset + 14]] +
byteStrings[array[offset + 15]];
this.offset += 16;
return guid;
}
}
byteStrings
甚至可能只是一个简单的数组文字,尽管一次性创建循环应该不是问题:
const byteStrings = [ "00", "01", "02", "03", "04", "05", "06", /*...*/, "ff"];
但同样,对这两者都持保留态度,并进行分析/基准测试,看看是否有帮助。
评论
0赞
Jochen Kühner
11/8/2023
喜欢这个主意!我将创建一个基准测试
0赞
Jochen Kühner
11/8/2023
看起来它快了近 5 倍。jsbench.me/c6loosw7fx/1
0赞
T.J. Crowder
11/8/2023
太好了,很高兴有帮助!我认为查找可能特别有帮助。:-)(事实上,这似乎是一个大问题,尽管这件事也有帮助。[jsbench.me 不允许我保存 2048 个字符>设置块。 jsben.ch 没有那么严格,但显示的结果与我无法保存的 jsbench.me 测试相似。 🤷 ♂️希望您在实际使用中看到类似的改进。const
评论