加快Java线程的速度

时间:2018-12-21 17:21:39

标签: javascript web-worker

最近,我一直在尝试使用 Web worker 界面来尝试JavaScript中的线程。

按照以下步骤尝试使Web工作人员包含

  • 将初始数组拆分为相等大小的片段
  • 为每个运行 .contains 的作品创建一个网络工作者
  • 如果在任意段中都找到了该值,则它返回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'})); }

任何浏览器和cpu都尝试过,与仅对初始数组进行包含相比,它非常慢。

为什么这么? 上面的代码有什么问题?

参考

编辑:问题与.contains()无关,但可能与其他数组函数有关,例如.indexOf()、. map(),forEach()等。为什么在网络工作者之间分配工作需要更长的时间...

2 个答案:

答案 0 :(得分:1)

这是一个人为的示例,因此很难帮助您针对要尝试做的事情进行优化,但是一个容易被忽视且可修复的缓慢路径是将数据复制到网络工作者。如果可能的话,您可以使用ArrayBuffers和SharedArrayBuffers在Web Worker之间快速传输数据。

您可以使用postMessage函数的第二个参数将arrayBuffer的所有权转让给Web Worker。重要的是要注意,该缓冲区将在Web工作者 back 传输之前不再可被主线程使用。 SharedArrayBuffers没有此限制,许多工作人员可以一次读取,但出于安全考虑,不一定在所有浏览器中都支持(请参阅mdn for more details

例如

const arr = new Float64Array(new ArrayBuffer(40000000 * 8));

console.time('posting');
ww.postMessage(arr, [ arr.buffer ]);
console.timeEnd('posting');

大约需要0.1毫秒的时间来运行

const arr = new Array(40000000).fill(0);

console.time('posting');
ww.postMessage(arr, [ arr ]);
console.timeEnd('posting');

大约需要10000ms才能运行。这只是为了传递消息中的数据,而不是运行辅助逻辑本身。

您可以阅读有关postMessage transferList参数here和可转移类型here的更多信息。重要的是要注意,您的示例进行时序比较的方式也包括Web工作者的创建时间,但是希望这可以为您带来大量时间,以及如何更好地解决这个问题的更好的主意。 / p>

答案 1 :(得分:0)

与简单的t0相比,您在t1contains之间要做的工作更多。这些额外的步骤包括:

  1. 转换函数->字符串->正则表达式-> blob->对象网址
  2. 呼叫新工作人员->解析对象网址-> JS引擎解释代码
  3. 发送网络工作数据->在主线程上序列化->在worker中反序列化(可能在实际复制的内存结构中,所以不会超级慢)

最好先创建线程,然后连续处理数据。它可能不会更快,但不会锁定您的UI。 另外,如果您反复搜索数组,我建议您将其转换为键为数组值且值为索引的映射。

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