Re: Sync API for workers

On Wed, Sep 5, 2012 at 8:07 PM, Glenn Maynard <glenn@zewt.org> wrote:
> On Wed, Sep 5, 2012 at 2:49 AM, Jonas Sicking <jonas@sicking.cc> wrote:
>>
>> The problem with a "Only allow blocking on children, except that
>> window can't block on its children" is that you can never block on a
>> computation which is implemented in the main thread. I think that cuts
>> out some major use cases since todays browsers have many APIs which
>> are only implemented in the main thread.
>
> You can't have both--you have to choose one of 1: allow blocking upwards, 2:
> allow blocking downwards, or 3: allow deadlocks.  (I believe #1 is more
> useful than #2, but each proposal can go both ways.  I'm ignoring more
> complex deadlock detection algorithms that can allow both #1 and #2, of
> course, since that's a lot harder.)

Indeed. But I believe #2 is more useful than #1. I wasn't proposing
having both, I was proposing only doing #2.

It's actually technically possible to allow both #1 and #2 without
deadlock detection algorithms, but to keep things sane I'll leave that
as out of scope for this thread.

[snip]
> I think that's by far the most
> interesting category of use cases raised for this feature so far, the
> ability to implement sync APIs from async APIs (or several async APIs).

That is certainly an interesting use case. I think another interesting
use case is being able to write synchronous APIs in workers whose
implementation uses APIs that are only available on the main thread.

That's why I'm not interested in only blocking on children, but rather
only blocking on parents.

>> The fact that all the examples that people have used while we have
>> been discussing synchronous messaging have spun event loops in
>> attempts to deal with messages that couldn't be handled by the
>> synchronous poller makes me very much think that so will web
>> developers.
>
> getMessage doesn't spin the event loop.  "Spinning the event loop" means
> that tasks are run from task queues (such as asynchronous callbacks) which
> might not be expecting to run, and that tasks might be run recursively; none
> of that that happens here.  All this does is block until a message is
> available on a specified port (or ports), and then returns it--it's just a
> blocking call, like sync XHR or FileReaderSync.

The example from Olli's proposal 3 does what effectively amounts to
"spinning an event loop". It pulls out a bunch of events from the
normal event loop and then manually dispatches them in a while loop.
The behavior is exactly the same as spinning the event loop (except
that non-message tasks doesn't get dispatchet).

>> I think this is fairly well illustrated by the set of rules that you
>> ended up having to set up in order to make the "blocking permitted"
>> flags work out correctly.
>
> Explaining this to users is simple: "if you want to block on a port, it
> needs to only ever be transferred above its other side, not below".

Claiming that we don't need to explain all edge cases to authors and
just give them a simplified version would, I think, be ignoring the
complexity of software that people write using the web platform.

> On Wed, Sep 5, 2012 at 9:03 PM, Jonas Sicking <jonas@sicking.cc> wrote:
>>
>> The part that I dislike about having single channel used for both sync
>> and async messaging is that you end up with one or more async
>> listeners which expect to get notified about all incoming messages,
>> but then you have an API which "steals" a message away from those
>> listeners. On top of that it has to do that stealing without any way
>> of ensuring ensuring that it actually steals the right message.
>
> That's exactly the reason to use MessagePorts: to categorize messages.

So it sounds like you are ok with not permitting the using both
synchronous and asynchronous messages to the same port then? As long
as some ports allow synchronous messages and others allow asynchronous
messages. Leaving aside the issue of how and when it is determined
that a port is sync vs. async.

>> But being (mostly) agnostic to if the other side is using sync
>> messages or not doesn't mean that the other side uses both sync and
>> async messaging!
>
> But you still have to do extra work on the sending side to support both sync
> and async receiving, since you have to hand it the right type of channel.

Unless you structure you code such that it's the responsibility of the
consumer of the API to create the channel. That way the consumer of
the API can choose if it wants to use blocking or non-blocking.

> Couldn't we just make calling getMessage permanently disable .onmessage
> dispatching (perhaps until the port is posted again)?  That would make it
> very hard to accidentally use both, while encapsulating knowledge about
> which way it's being used to the receiver, so the sender doesn't need to
> carefully send the receiver the right "type" of MessageChannel.  (I really
> don't feel this is necessary, but I'd prefer it to multiple MessagePort
> interfaces.)

We could define that calling .start() sets the port in "async mode",
at which point .getMessage() throws an exception. And calling
getMessage() sets the port in "sync mode" which makes .start() throw
an exception.

But that would still lose the nice behavior of having sync-enabled
channels throw if you try to pass them to the wrong place.

And do note that even your proposal requires the async side of a
message channel to be aware of that the other side might be using
synchronous polling. If it wants to support the other side polling
messages synchronously, it needs to take care not to pass its end of
the channel to the "wrong" places.

I'm suggesting formalizing that by using different types.

Yes, I do acknowledge that it's less flexible than using the same
MessagePorts objects for both sync and async, but I think the added
ease of debugging is worth it. The disadvantage with separate types
doesn't seem huge, it just means that you either have to structure the
code such that you accept an MessagePort rather than send one, or
accept a flag indicating what type of channel to create.

/ Jonas

Received on Thursday, 6 September 2012 05:32:31 UTC