
Tasklets: a more ergonomic solution to WebWorkers - guifortaine
https://github.com/GoogleChromeLabs/tasklets
======
dassurma
Hey everyone, proposal author here :D Surprised to see this show up on HN
_now_, since the WICG discussion[1] has been held a good while ago.

The things that have been pointed out here are similar to the feedback we’ve
gotten from other browser vendors. Most crucially: We might be conflating two
separate improvements here. On the one hand, there’s the ergonomics feature of
async-ifying remote value and on the other introducing custom worklets that
can share OS threads.

As a result, I have extracted the magic sauce from the tasklets polyfill into
its own library “Comlink”[2] and I plan to write a couple of web apps using it
to gather some perf data. With that data we can hopefully figure out if the
ergonomics layer is worth standardizing.

Same goes for the worklets. I’ll be using good old web workers and see how big
the perf impact is. With that data we can hopefully figure out if we “just”
need to optimize Workers or if there’s some gains that can only be reaped by
the worklet approach.

[1]: [https://discourse.wicg.io/t/proposal-
tasklets/2199](https://discourse.wicg.io/t/proposal-tasklets/2199) [2]:
[https://github.com/GoogleChromeLabs/comlink](https://github.com/GoogleChromeLabs/comlink)

------
Lerc
I'm not sure how this addresses the resource load of Web Workers. What about
their alternative makes it inherently lighter?

I agree that there is an issue here, but this feels like making another thing
with bits added. To genuinely make it lighter weight, would it not need to be
a subset of capability. Otherwise why couldn't the efficiency just be added to
Workers?

The problem seems to be that Workers can only really applied to fairly
substantial workloads. Trivial tasks (x=y+1) can be done on the main
JavaScript Thread. There needs to be something for the middle ground.

At a minimum I would have thought that such a solution should enable a
parallel form of map, filter, and reduce style operations. These are
operations that are intrinsically designed for non-trivial tasks.

I feel that there might need to be a way to distinguish some sort of function
purity before such parallelism is allowed, lest JavaScript turn into a soup of
races and conflicts. A way to declare (or ideally automatically identify)
functions that do not mutate global state and return a value created from
inside the function.

Workers handle persistent parallel processing with async communication. I
suspect maintaining that complete persistent state is why the resource load is
so high. The lightweight middle-ground should offer non-persistent
parallelism.

~~~
jerf
"I'm not sure how this addresses the resource load of Web Workers. What about
their alternative makes it inherently lighter?"

The running of multiple tasklets within one WebWorker, from the sounds of it.

Given that there is a polyfill directory in the repo, and that nothing in what
they've described immediately strikes me as needing any more browser support
(give or take perhaps some quirky corner) for an initial implementation, it
sounds like it's mostly stuff you could in theory write yourself. There's
probably hundreds of similar things out there in the world already. But
standardizing is often helpful, and there are ways the browser engine could
theoretically accelerate these methods if they are explicitly supported with
defined semantics the browser can understand. In particular, if the JIT can
prove you are sending a "message" using this API that is a pure data object,
it doesn't have to serialize that to a bytestream on one side and deserialize
it on the other; it can just transfer the object via pointer passing. Or if it
must still serialize/deserialize across a boundary, at least use a mechanism
written in C++ that can be more efficient and easier than anything you can
write in native JS.

(I say 'browser' above to leave open the possibility of DOM node proxying or
whathaveyou; of course it would work in Node too.)

"At a minimum I would have thought that such a solution should enable a
parallel form of map, filter, and reduce style operations. These are
operations that are intrinsically designed for non-trivial tasks."

Surely these already exist somewhere? (If I know my JS library world, several
dozen times over.) They should transfer over into the tasklet just fine.

Not sure this is worth it's own comment, so I'll just add that this strikes me
as putting apartment-style threading into the browser:
[https://msdn.microsoft.com/en-
us/library/ms809971.aspx](https://msdn.microsoft.com/en-
us/library/ms809971.aspx) based on a cooperative scheduling process, built on
top of a dynamic scripting language. This would put the browser tech stack now
somewhere in 2000-2001, I think. (This style of threading leans 1990s, but JS
is better than any dynamic scripting language was in that timeframe, so I'll
bump it forward a bit. But then back again for being cooperatively threaded.)
It's getting there...

But in all seriousness, to the team looking at this, I would strongly suggest
considering what this means in a world of WebAssembly, not just pure JS.
Perhaps it all just works as-is, but it would still be nice to see some text
about it.

~~~
Lerc
>Surely these already exist somewhere? (If I know my JS library world, several
dozen times over.)

The problem is the access to data. You have to pass data to a Worker. To take
the canonical embarrassingly parallel task, ray-tracing, each ray can be
executed in parallel but they all refer to a common scene. Passing the scene
on a per-ray basis would lose any gains. Passing a scene then doing a batch of
rays is only 'slightly parallel'

consider a list of points and you want to make a table showing their relative
distances

    
    
        var  distances = list.map(a=>list.map(b=>distance(a,b)));
    

That's something that has plenty of potential for parallelism, but to do so
the function inside the first map also needs be able to see the list. What I
really want is something where I can write a piece of code as simple as that
where it will run on as many cores as the host device has available.

~~~
CuriousSkeptic
You would need immutability (or a static type system) to do that safely
though. And I don’t think you can check the closed over objects before the
closure is actually scheduled to execute (perhaps if you limit the closure to
const references)

But, since you can pass a context explicitly to map and friends you might get
away with checking that for immutability.

------
trgv
It's not immediately clear to me how this proposal differs from "a nicer
JavaScript wrapper around Web Workers."

Don't get me wrong, I'm hugely in favor of that being added to the language,
but I feel like the readme somewhat overstates what this actually is. I may
have misunderstood something.

~~~
dassurma
Please see my top-level reply :)

------
iainmerrick
If Chrome’s implementation of web workers is too heavyweight, that’s Chrome’s
problem.

I don’t think there’s anything in the existing spec that makes it inherently
heavyweight (or if there is, this new proposal doesn’t explain the problem).

Current standards shouldn’t be thrown out and rewritten on a whim. All else
being equal, current standards should be supported forever.

If you still really really want to rewrite some bit of HTML5 from scratch,
start with Web Audio.

~~~
dassurma
> If Chrome’s implementation of web workers is too heavyweight, that’s
> Chrome’s problem.

You absolutely have a point. Ben Kelly from Mozilla pointed out to use that
their workers are _much_ cheaper than ours. We apparently never invested much
time in optimizing Workers as they are rarely used.

------
acjohnson55
The part about not being able to use a transferred value seems tricky to me.
What happens when there's a function call in between, or dynamic dispatch?

