我的应用程序产生一个Web Worker,它处理许多不同的任务,对于具有大量数据集的计算密集型任务,web worker产生更多的“子worker”来使用整个可用的CPU能力,即第一个worker和子worker以相等的份额进行处理。完成后,必须使用postMessage()将结果返回到主线程(从第一个web worker开始,它工作得很好)。
Main thread <--> Web Worker <--> 2-4 Sub-Workers如何从子工作线程向主线程发送带有可传输数组缓冲区的消息?如果我使用self.postMessage(),消息将转到第一个"Web Worker“。
发布于 2020-11-25 10:31:25
您可以将MessageChannel传递给您的子工作人员。
如果您从未使用过它,我邀请您阅读我的,它解释了这个API的基础知识。
这是一个演示,其中主线程生成MessageChannel,然后主工作线程将发送的MessagePort传递给子工作线程,子工作线程现在可以直接与主线程通信和传输数据。
const sub_worker_url = makeWorkerURL( `
onmessage = (evt) => {
// grab the MessagePort
// now we can communicate directly with main
const port = evt.ports[ 0 ];
// do some computation
const chunk = new Uint8Array( 256 );
crypto.getRandomValues( chunk );
// send the buffer to main directly
port.postMessage( chunk, [ chunk.buffer ] );
};
` );
const main_worker_url = makeWorkerURL( `
onmessage = (evt) => {
const subworker = new Worker( "${ sub_worker_url }" );
// transfer the MessagePort to the subworker
subworker.postMessage( "", [ evt.ports[ 0 ] ] );
};
` );
const main_worker = new Worker( main_worker_url );
// sub-worker will talk to us directly trhough this channel
const channel = new MessageChannel();
// we listen in one of the two ports
channel.port1.onmessage = ({ data }) => console.log( "received in main", data );
// we transfer the port to the worker,
// which will itself transfer it to the sub-worker
main_worker.postMessage("", [channel.port2]);
function makeWorkerURL( content ) {
const blob = new Blob([content], { type: "text/javascript" });
return URL.createObjectURL( blob );
}
显然,您也可以通过主工作进程生成MessageChannels并将两个端口传递给主工作进程和子工作进程的方式来重写此代码:
const sub_worker_url = makeWorkerURL( `
// same as in previous demo
onmessage = (evt) => {
const port = evt.ports[ 0 ];
const chunk = new Uint8Array( 256 );
crypto.getRandomValues( chunk );
port.postMessage( chunk, [ chunk.buffer ] );
};
` );
const main_worker_url = makeWorkerURL( `
const ports = [];
for( let i = 0; i < navigator.hardwareConcurrency - 2; i++ ) {
const channel = new MessageChannel();
const subworker = new Worker( "${ sub_worker_url }" );
// transfer one of the MessagePorts to the subworker
subworker.postMessage( i, [ channel.port1 ] );
ports.push( channel.port2 );
};
// [optional] (we could send one message per port in the loop)
// send all the generated ports to main
// in a single message
self.postMessage( "", ports );
` );
const main_worker = new Worker( main_worker_url );
main_worker.onmessage = ({ ports }) => {
ports.forEach( (port, index) => {
port.onmessage = ({ data }) =>
console.log( "received in main from subworker #" + index, data.slice( 0, 5 ), "..." );
} );
};
function makeWorkerURL( content ) {
const blob = new Blob([content], { type: "text/javascript" });
return URL.createObjectURL( blob );
}
设计由你决定。
现在,根据您的情况和您需要支持的浏览器,您可能还想研究SharedArrayBuffers,它听起来更适合您的情况,因为所有工作人员都可以在相同且唯一的buffer上工作,但不幸的是,该API没有得到广泛支持(基本上只有Blink浏览器支持)。
https://stackoverflow.com/questions/64956104
复制相似问题