V8 和大字符串比较性能对字符串进行哈希处理影响很大?

问题描述 投票:0回答:1

背景:我正在节点端构建后端并优化带宽。基本上我试图不发送客户端已经拥有的缩略图(存储为 10KiB 字符串),yada yada,在短时间内我直接比较缩略图数据,因为我无法确定它们是否已更新但已移动此后采取不同的解决方案。这只是一个好奇心,不再有任何实际意义。

好吧,我在 V8 中发现了这种行为,默认情况下,大字符串比较很慢,但是(大概)对这些字符串进行哈希处理(例如将它们粘贴到 Set 中),比较速度会加快很多。我已经确认这发生在节点以及基于铬的电子前端。

示例:

    (()=>{
        //  making 10k character strings
        const big_strings = [];
        const palette = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        for (let i = 0; i < 100; i++) {
            let big_string = "";
            for (let i = 0; i < 10_000; i++) {
                big_string += palette[Math.floor(Math.random() * palette.length)];
            }
            big_strings.push(big_string);
        }

        //  comparison functions
        function cmp1(a, b) {
            return a === b;
        }

        function cmp2(a, b) {
            const lol = new Set();
            lol.add(a);
            lol.add(b);
            return a === b;
        }

        //  tests
        let sorted_1, sorted_2;

        console.time("Test 1");
        for (let i = 0; i < 100; i++) {
            sorted_1 = big_strings.slice();
            sorted_1.sort(cmp1);
        }
        console.timeEnd("Test 1");

        console.time("Test 1");
        for (let i = 0; i < 100; i++) {
            sorted_1 = big_strings.slice();
            sorted_1.sort(cmp1);
        }
        console.timeEnd("Test 1");

        console.time("Test 1");
        for (let i = 0; i < 100; i++) {
            sorted_1 = big_strings.slice();
            sorted_1.sort(cmp1);
        }
        console.timeEnd("Test 1");

        console.time("Test 2");
        for (let i = 0; i < 100; i++) {
            sorted_2 = big_strings.slice();
            sorted_2.sort(cmp2);
        }
        console.timeEnd("Test 2");

        console.time("Test 1");
        for (let i = 0; i < 100; i++) {
            sorted_1 = big_strings.slice();
            sorted_1.sort(cmp1);
        }
        console.timeEnd("Test 1");

        //  sanity check
        let good = 0;
        const total = Math.max(sorted_1.length, sorted_2.length);
        for (let i = 0; i < total; i++) {
            if (sorted_1[i] === sorted_2[i]) {
                good++;
            } else {
                throw("Results do not match.");
            }
        }
        console.log(`Sanity check OK ${good} / ${total}`);


    })();

在示例中,有两个比较函数,一个简单地执行 a === b,另一个首先将 a 和 b 粘贴到一次性 Set 中。我可以根据需要多次使用第一个比较函数运行测试(本例中为 3 次),但它总是很慢。然后我使用第二个比较函数运行测试一次,之后,对这些特定字符串的所有测试都会非常快。

这种行为会带来什么后果?为什么 V8 不在后台对字符串本身进行哈希处理?

javascript v8
1个回答
0
投票

这里不进行比较,而是进行相等,并且似乎使用

Set
可以优化它。 Afaik V8 字符串是对象,并且可能存在与
Set
相关的一些相等性检查兑现,因为有一个全局字符串注册表,并且相同的字符串是相同的字符串对象。

确实可能会发生一些哈希、缓存和优化,但我根本不会依赖它们。该实现是一个黑匣子,所以不要尝试施展魔法。

关于您的示例,创建集合时对实际比较没有帮助,只会减慢速度。

` Chrome/123
---------------------------------------------------------------------------------
>              n=10        |      n=100       |     n=1000      |     n=10000    
Test 1   ■ 1.00x x100k 692 | ■ 1.00x x10k 338 | ■ 1.00x x1k 138 | ■ 1.00x x10  56
Test 2     1.18x x100k 819 |   1.74x x10k 589 |   2.87x x1k 396 |   1.96x x10 110
---------------------------------------------------------------------------------
https://github.com/silentmantra/benchmark `

//  making 10k character strings
let $length = 10;
const big_strings = [];
const palette = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
for (let i = 0; i < $length; i++) {
    let big_string = "";
    for (let i = 0; i < 10_0; i++) {
        big_string += palette[Math.floor(Math.random() * palette.length)];
    }
    big_strings.push(big_string);
}

let $input = big_strings;

//  comparison functions
function cmp1(a, b) {
    return a > b ? 1 : a < b ? -1 : 0;
}

function cmp2(a, b) {
    const lol = new Set();
    lol.add(a);
    lol.add(b);
    return a > b ? 1 : a < b ? -1 : 0;
}


// @benchmark Test 1
$input.toSorted(cmp1);

// @benchmark Test 2
$input.toSorted(cmp2);



/*@skip*/ fetch('https://cdn.jsdelivr.net/gh/silentmantra/benchmark/loader.js').then(r => r.text().then(eval));

© www.soinside.com 2019 - 2024. All rights reserved.