代码之家  ›  专栏  ›  技术社区  ›  Jannes Botis

让Javascript线程快速运行

  •  0
  • Jannes Botis  · 技术社区  · 6 年前

    网络工作者

    试图使 包含

    • 将初始数组拆分为大小相等的块
    • .包含
    • 如果在任何一个片段中找到该值,它将返回true,而无需等待所有工作人员完成。

    以下是我尝试过的:

    var MAX_VALUE = 100000000;
    var integerArray = Array.from({length: 40000000}, () => Math.floor(Math.random() * MAX_VALUE));
    
    var t0 = performance.now();
    console.log(integerArray.includes(1));
    var t1 = performance.now();
    console.log("Call to doSomething took " + (t1 - t0) + " milliseconds.");
    
    var promises = [];
    var chunks = [];
    while(integerArray.length) {
        chunks.push(integerArray.splice(0,10000000));
    }
    
    t0 = performance.now();
    chunks.forEach(function(element) {
        promises.push(createWorker(element));
    });
    
    function createWorker(arrayChunk) {
        return new Promise(function(resolve) {
            var v = new Worker(getScriptPath(function(){
                self.addEventListener('message', function(e) {
                    var value = e.data.includes(1);
                    self.postMessage(value);
                }, false);
            }));
            v.postMessage(arrayChunk);
            v.onmessage = function(event){
                resolve(event.data);
            };
        });
    }
    
    firstTrue(promises).then(function(data) {
        // `data` has the results, compute the final solution
        var t1 = performance.now();
        console.log("Call to doSomething took " + (t1 - t0) + " milliseconds.");
    });
    
    function firstTrue(promises) {
        const newPromises = promises.map(p => new Promise(
            (resolve, reject) => p.then(v => v && resolve(true), reject)
    ));
       newPromises.push(Promise.all(promises).then(() => false));
        return Promise.race(newPromises);
    }
    
    //As a worker normally take another JavaScript file to execute we convert the function in an URL: http://stackoverflow.com/a/16799132/2576706
    function getScriptPath(foo){ return window.URL.createObjectURL(new Blob([foo.toString().match(/^\s*function\s*\(\s*\)\s*\{(([\s\S](?!\}$))*[\s\S])/)[1]],{type:'text/javascript'})); }

    到初始数组。

    为什么会这样 缓慢的 ? 上面的代码有什么问题?

    编辑:问题不在于具体的.contains(),而可能是其他数组函数,例如.indexOf()、.map()、forEach()等。为什么在web工作人员之间拆分工作需要更长的时间。。。

    2 回复  |  直到 4 年前
        1
  •  1
  •   Garrett Johnson    6 年前

    这是一个有点做作的例子,因此很难帮助您针对具体要做的事情进行优化,但一个容易被忽略且可修复的慢路径是将数据复制到web worker。如果可能的话,您可以使用ArrayBuffers和SharedArrayBuffers在web工作人员之间快速传输数据。

    您可以使用postMessage函数的第二个参数将arrayBuffer的所有权转移给web工作者。需要注意的是,在主线程传输缓冲区之前,该缓冲区将不再可用 返回 mdn for more details )

    例如

    const arr = new Float64Array(new ArrayBuffer(40000000 * 8));
    
    console.time('posting');
    ww.postMessage(arr, [ arr.buffer ]);
    console.timeEnd('posting');
    

    const arr = new Array(40000000).fill(0);
    
    console.time('posting');
    ww.postMessage(arr, [ arr ]);
    console.timeEnd('posting');
    

    运行约10000毫秒。这只是为了传输消息中的数据,而不是运行工作逻辑本身。

    here 和可转移类型 here . 需要注意的是,您的示例进行时间比较的方式也包括web worker创建时间,但希望这能更好地了解大量时间的去向以及如何更好地利用这些时间。

        2
  •  0
  •   Mendy    6 年前

    你在两人之间做了很多工作 t0 t1 与简单的 contains . 这些额外步骤包括:

    1. 呼叫新员工->解析对象URL->JS引擎解释代码
    2. 发送网络工作数据->在主线程上序列化->在worker中反序列化(可能是在内存中复制的结构,所以不是超慢)

    最好先创建线程,然后继续处理数据。它可能不会更快,但不会锁定您的UI。

    例如 ['apple', 'coconut', 'kiwi'] 将转换为 { apple: 1, coconut: 2, kiwi:3 } 通过地图进行搜索将在摊销正常时间内进行(快速),而数组将是线性搜索(对于大型集合,速度非常慢)。