【问题标题】:Using transferable objects from a Web Worker使用来自 Web Worker 的可传输对象
【发布时间】:2013-04-10 20:59:44
【问题描述】:

我目前有这个代码来创建一个 Web Worker:

w = new Worker("webwork.js");
w.onmessage = function(event) { alert(event.data); }

然后是 Web Worker 的 webwork.js 代码:

self.onmessage = function(event) {
    //var ss=r;  //Causes error because of undefined
    var ss="";
    for(var currProp in event) {
        ss+=("event."+currProp+"="+event[currProp]+"\n");
    }
    postMessage(ss);
}

现在我想用这个代码传输一个 128 兆字节的ArrayBuffer

var r = new ArrayBuffer(1048576*128);
w.postMessage(0, [r]);

现在我应该已经传输了变量r,我如何从 Web Worker 本身访问它。我试过event.r,只是rself.r 和其他一些东西,比如尝试为ArrayBuffers 的数组添加第二个函数参数,但没有任何效果。

如何从 Web Worker 访问传输的变量?

【问题讨论】:

  • 不会在event.data吗?
  • 似乎并非如此。如果我使用“w.postMessage(0,[r]);”,那么“event.data”就是 0,但我不知道 ArrayBuffers 数组的位置,即使通过检查所有属性事件。我找不到它。

标签: javascript web-worker transferable


【解决方案1】:

试试 w.postMessage([0,r])。要使用可转移对象,需要将数组缓冲区作为数组的第二项传递。见this

【讨论】:

    【解决方案2】:

    这对我有用:

    //在主目录中

    var x = new ArrayBuffer(1048576*128);
    w.postMessage({buffer: x});
    

    // 在工作线程中,在消息处理程序中,

    processMessage: function(ev){
        var buffer = ev.data.buffer,
        // other stuff . buffer is referenced correctly here. 
    }
    

    【讨论】:

    • 这只会克隆 ArrayBuffer;不在线程之间转移所有权。
    【解决方案3】:

    sbr 给出的答案有效,但它会导致在发送给工作人员之前制作数据副本。对于大量数据,这可能会很慢。
    要使用“可转让对象”,您实际上将对象的所有权转移到网络工作者或从网络工作者转移。这就像在没有复制的地方通过引用传递。它与普通的按引用传递的区别在于,传输数据的一方无法再访问它。

    我相信您应该在示例中发送数据的方式是:

    w.postMessage(r,[r]);  // first arg is r, not 0 as in the question
    

    以及您在网络工作者中访问它的方式:

    addEventListener('message', function(event) {
        var r = event.data;
    });
    

    在我自己的应用程序中,我需要将一个大型类型的 Float64Array 从 web worker 发送到主线程,而不会影响副本的性能。这需要大量的反复试验和搜索,所以我认为我应该在此处为遇到类似问题的其他人提供该示例。
    这是在工作端工作的代码(arr 是我的 Float64Array):

    self.postMessage(arr.buffer, [arr.buffer]);
    

    在接收主线程上我有:

    theWorker.addEventListener('message', function(ev) {
        var arr = new Float64Array(ev.data);  // just cast it to the desired type - no copy made
        // ...
    });
    

    请注意,这在 Chrome 中有效,但截至目前,可能不适用于大多数其他浏览器(尚未尝试过。)

    另外,如果你想发送除了大数组之外的其他信息,你可以这样做:

    self.postMessage({foo:"foo", bar:arr.buffer}, [arr.buffer]);
    

    在接收(在本例中为主)线程:

    theWorker.addEventListener('message', function(event) {
        var foo = event.data.foo;
        var arr = new Float64Array(event.data.bar);  // cast it to the desired type
        // ...
    });
    

    【讨论】:

    • 这个答案比公认的答案更好,因为它更好地解释了第二个数组参数的用途。
    【解决方案4】:
    PostMesage(aMessage, transferList)
    

    transferList 中,您必须指定可转移对象,这些对象包含在aMessage 中:

    var objData =
    {
        str: "string",
        ab: new ArrayBuffer(100),
        i8: new Int8Array(200)
    };
    objWorker.postMessage(objData, [objData.ab, objData.i8.buffer]);
    

    另一边:

    self.onmessage = function(objEvent)
    {
        var strText = objEvent.data.str;
        var objTypedArray = objEvent.data.ab;
        var objTypedArrayView = objEvent.data.i8;
    }
    

    【讨论】:

    • 有谁知道这是转让所有权还是复制?我试过了,它看起来像是在转移所有权。
    • 只创建一次 ArrayBuffer 和 Int8Array!然后继续来回发送。否则使用可转移对象根本没有意义。
    • @Pawel 你能详细说明如何继续来回发送它吗?收到数组后,如果您再次尝试 postMessage,浏览器会抱怨“索引 0 处的 ArrayBuffer 已被绝育。”
    • @dooderson 回答有点晚了,但为了后代:是的,这会转移所有权(developer.mozilla.org/en-US/docs/Web/API/Transferable)。我假设它保持原子性
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-07
    • 1970-01-01
    • 2017-02-01
    • 2017-01-20
    • 2010-10-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多