padolsey / operative

:dog2: Seamlessly create Web Workers

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Transferable objects

Rich-Harris opened this issue · comments

This is a slightly speculative issue but I thought it worth raising - do you have any plans to support transferable objects?

For anyone not familiar: transferable objects allow you to transfer an ArrayBuffer (and also a CanvasProxy or MessagePort, whatever they are!) to and from a web worker - rather than using the structured cloning algorithm, the reference to a transferable object is 'neutered' once it's transferred - the chunk of memory actually changes owner.

I'm using operative in a project that deals with large amounts of binary data. I've implemented support for transferables in my local copy of the library, and it's blazing fast. If it's useful I can tidy up the code and share it when I get a chance (it's probably not PR-worthy yet).

This is a heavily condensed illustration of how I'm using it:

projectGeometry = operative( function ( arrayBuffer ) {
  var d = this.deferred();

  float32Array = doSomeComplexMathsAndReturnATypedArray( arrayBuffer );
  d.transfer( float32Array.buffer );
}, [ 'poly2tri.min.js' ]);

// `buffer` comes straight from an xhr with responseType: 'arraybuffer'
projectGeometry.transfer( buffer ).then( function ( resultBuffer ) {
  var typedArray = new Float32Array( resultBuffer );
  doSomethingWith( typedArray );
});

An alternative API is to specify the data and the transfer list separately (which is how it works under the hood with postMessage:

w = operative( function ( foo, typedArray, anotherTypedArray ) {
  var d = this.deferred();

  /* some code happens... */

  d.transfer({ aThing: 42, anotherThing: myTypedArray }, [
    // list of objects to transfer from worker
    myTypedArray.buffer
  ]);
});

w.transfer( foo, typedArray, anotherTypedArray, [
  // list of objects to transfer to worker
  typedArray.buffer,
  anotherTypedArray.buffer
]).then( handleResult );

It's fairly easy to detect support for transferables (you just try transferring an array buffer and see if the byteLength falls to zero - article), and falling back to structured cloning works just fine.

Hi -- sorry for this crazily late reply! I'll have a deeper look into this when time permits, but it definitely looks like something operative should support. I think I did consider it right at the beginning but I couldn't figure out a clear path to degradation, and wasn't sure about including non-degradable things in operative's core API. Maybe the transfers thing should be in the form of a plugin? Not sure.

If you have time to submit a PR (even messy code is ok) that'd be really great -- I'd like to experiment a bit with it.

Will try and send a PR in the next few days, as soon as I've had a chance to do some post-launch cleanup and consolidation. The project we launched today uses the modified version I referred to above. We're using it to triangulate and project a load of geometry onto a sphere - the end result is quite chunky, and structured cloning is slower than ideal, so the input 2d geometry and the output 3d geometry are transferred as ArrayBuffers. Our version of operative exposes a property called hasTransferableSupport, but we don't actually use it - the transfer methods just fall back to structured cloning in environments that don't support transferables, so it's a fairly low-effort progressive enhancement.

Congrats on the launch! Out of curiosity are you pooling workers/operatives for machines with > 1 core?

How does this look? -- https://github.com/padolsey/operative/wiki/Transfers-API (this is what I'm currently implementing for a 0.4 rc.

@padolsey - Looks good. One small note, I don't believe Transferable
Objects are a feature of postMessage, though that might have been one of
the earliest uses.

On Mon, Oct 6, 2014 at 11:35 PM, James Padolsey notifications@github.com
wrote:

How does this look? --
https://github.com/padolsey/operative/wiki/Transfers-API (this is what
I'm currently implementing for a 0.4 rc.


Reply to this email directly or view it on GitHub
#23 (comment).

That's true -- but I meant that transferring Transferable objects via postMessage is a feature of postMessage... but that's all needlessly convoluted ... so I'll change the wording :D

This is now available in 0.4.0-rc1 (via npm). Branch is 0-4-rc1.

This is awesome! Sorry I never got round to sending that PR - probably for the best, your implementation is a good bit neater than the hacks we shipped our project with :-)