让Javascript线程快速运行

让Javascript线程快速运行,javascript,web-worker,Javascript,Web Worker,最近我一直在尝试使用webworkers界面来试验JavaScript中的线程 尝试使用web workers制作包含,请执行以下步骤: 将初始数组拆分为大小相等的块 为每个运行的工件创建一个web worker。包含该工件上的 如果在任何一个片段中找到该值,它将返回true,而无需等待所有工作人员完成 以下是我尝试过的: var最大值=100000000; var integerArray=Array.from({length:40000000},()=>Math.floor(Math.

最近我一直在尝试使用webworkers界面来试验JavaScript中的线程

尝试使用web workers制作包含,请执行以下步骤:

  • 将初始数组拆分为大小相等的块
  • 为每个运行的工件创建一个web worker。包含该工件上的
  • 如果在任何一个片段中找到该值,它将返回true,而无需等待所有工作人员完成
以下是我尝试过的:

var最大值=100000000;
var integerArray=Array.from({length:40000000},()=>Math.floor(Math.random()*MAX_VALUE));
var t0=performance.now();
控制台日志(integerArray.includes(1));
var t1=performance.now();
log(“对doSomething的调用花费了”+(t1-t0)+“毫秒”);
var承诺=[];
var chunks=[];
while(整数数组长度){
push(integerArray.splice(010000000));
}
t0=性能。现在();
forEach(函数(元素){
promises.push(createWorker(元素));
});
函数createWorker(arrayChunk){
返回新承诺(函数(解析){
var v=新工作进程(getScriptPath(函数(){
self.addEventListener('message',函数(e){
var值=e.data.包括(1);
self.postMessage(值);
},假);
}));
v、 邮递(arrayChunk);
v、 onmessage=函数(事件){
解析(事件数据);
};
});
}
firstTrue(承诺)。然后(函数(数据){
//‘data’有结果,计算出最终的解决方案
var t1=performance.now();
log(“对doSomething的调用花费了”+(t1-t0)+“毫秒”);
});
函数firstTrue(承诺){
const newPromises=promises.map(p=>newpromise(
(解析,拒绝)=>p.then(v=>v&&resolve(true),拒绝)
));
newPromises.push(Promise.all(promises).然后(()=>false));
回报承诺。种族(新承诺);
}
//作为一名工作人员,通常会执行另一个JavaScript文件,因此我们将函数转换为URL:http://stackoverflow.com/a/16799132/2576706

函数getScriptPath(foo){return window.URL.createObjectURL(新Blob([foo.toString().match(/^\s*function\s*\(\s*)\s*{([\s\s](?!\}$)*[\s\s])[1]],{type:'text/javascript'}];}
与简单的
相比,您在
t0
t1
之间做了更多的工作。这些额外步骤包括:

  • 转换函数->字符串->正则表达式->blob->对象URL
  • 调用new worker->解析对象URL->JS引擎解释代码
  • 发送web工作数据->在主线程上序列化->在工作线程中反序列化(可能是在内存结构中复制的,所以不会超慢)
  • 最好先创建线程,然后继续处理数据。它可能不会更快,但不会锁定您的UI。 另外,如果您重复搜索数组,我建议将其转换为一个映射,其中键是数组值,值是索引

    e、 g。 数组
    ['apple','couch','kiwi']
    将转换为
    {apple:1,couch:2,kiwi:3}

    通过地图进行搜索将在摊销的正常时间(快)内进行,而数组将是线性搜索(对于大型集合,搜索速度非常慢)。

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

    您可以使用postMessage函数的第二个参数将arrayBuffer的所有权转移给web工作者。需要注意的是,该缓冲区在被web worker传回之前,将不再被主线程使用。SharedArrayBuffers没有此限制,可以由许多工作人员一次读取,但出于安全考虑,并非所有浏览器都支持SharedArrayBuffers(请参阅)

    比如说

    const arr = new Float64Array(new ArrayBuffer(40000000 * 8));
    
    console.time('posting');
    ww.postMessage(arr, [ arr.buffer ]);
    console.timeEnd('posting');
    
    运行时需要约0.1ms

    const arr = new Array(40000000).fill(0);
    
    console.time('posting');
    ww.postMessage(arr, [ arr ]);
    console.timeEnd('posting');
    
    运行约10000毫秒。这只是为了传输消息中的数据,而不是运行工作逻辑本身


    您可以阅读有关postMessage transferList参数和transferable类型的更多信息。需要注意的是,您的示例进行时间比较的方式也包括web worker创建时间,但希望这能更好地了解大量时间的去向以及如何更好地利用这些时间。

    我将做更多的研究,并发表更好的评论,但我想知道这是否是由于本机
    includes
    方法的性能缓慢造成的。。也许你是对的。。。我尝试将“promissions.push(createWorker(element));”改为“promissions.push(createWorker());”和“var value=e.data.includes(1);”改为“var value=false”;而且速度更快。。。似乎将数据复制到线程是一个问题。。。您能否提供一些代码,说明如何稍后传递数据,或者我是否可以共享同一个数组而不复制它?