首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将数据从Web Worker发送到主线程

将数据从Web Worker发送到主线程
EN

Stack Overflow用户
提问于 2020-11-22 23:42:20
回答 1查看 327关注 0票数 1

我的应用程序产生一个Web Worker,它处理许多不同的任务,对于具有大量数据集的计算密集型任务,web worker产生更多的“子worker”来使用整个可用的CPU能力,即第一个worker和子worker以相等的份额进行处理。完成后,必须使用postMessage()将结果返回到主线程(从第一个web worker开始,它工作得很好)。

代码语言:javascript
复制
Main thread <--> Web Worker <--> 2-4 Sub-Workers

如何从子工作线程向主线程发送带有可传输数组缓冲区的消息?如果我使用self.postMessage(),消息将转到第一个"Web Worker“。

EN

回答 1

Stack Overflow用户

发布于 2020-11-25 10:31:25

您可以将MessageChannel传递给您的子工作人员。

如果您从未使用过它,我邀请您阅读我的,它解释了这个API的基础知识。

这是一个演示,其中主线程生成MessageChannel,然后主工作线程将发送的MessagePort传递给子工作线程,子工作线程现在可以直接与主线程通信和传输数据。

代码语言:javascript
复制
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并将两个端口传递给主工作进程和子工作进程的方式来重写此代码:

代码语言:javascript
复制
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浏览器支持)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64956104

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档