Re: Sync API for workers

On Sun, Sep 2, 2012 at 12:24 PM, Andrew Wilson <atwilson@google.com> wrote:

> Just wanted to point out that all of the arguments for a wait-for-reply
> API in workers also apply to SharedWorkers. It's trickier for SharedWorkers
> since they use MessagePorts, and we probably don't want to expose this kind
> of API to pages (which also use MessagePorts). But I would strongly prefer
> a solution that would be applicable to all kinds of workers, not just
> dedicated workers.
>

You can do that by giving MessagePort another interface in workers, eg.
MessagePortSync or MessagePortWorkers, which inherits from MessagePort and
adds eg. getMessage().  It might need a bit of finessing to switch
interfaces during structured clone.

Alternatively--and as I type this I like it better--add a getMessage(port)
method to WorkerGlobalScope.  Simplicity aside, I like that it can
naturally support getMessage([port1, port2, port3], 100).  With
port.getMessage(), there's no way to wait for a message from multiple ports
(think select()/poll()).  This doesn't give any way to specify the worker's
implicit port, though; I guess that could be a special case, eg. pass in
null.

>
> I'm not entirely certain what the semantics of getMessage() are, though -
> if you grab a message via getMessage(), does this imply that normal
> onmessage event handlers are not run (or perhaps are run after we re-enter
> the event loop)?
>

It shouldn't still dispatch onmessage asynchronously.  That's confusing,
and also, it means the messages would build up in the queue until the
script returns.  Due to the nature of the feature, the script may not
return for a long time, or it may receive lots of messages before it does.
Also, if you may handle the message during processing (via getMessage), and
also when idle (via onmessage), this means it's hard to ensure you don't
process messages twice.

The two options that have come up are:

1: don't dispatch onmessage at all if getMessage returns a message.
getMessage() consumes the message from the queue.
2: dispatch onmessage synchronously, before returning from getMessage
(which can also return the message or not).

They're mostly equivalent; you can build either on top of the other.
(createEvent isn't actually exposed to WorkerGlobalScope in order to
implement #2 from #1, but that's a separate issue.)

I just noticed a strong argument against #2: it's recursive.  Without any
strong benefit, that seems like a good thing to avoid.

I am not optimistic that we can do deadlock prevention in the general case
> with MessagePorts, for the same reason that it's prohibitively difficult to
> reliably garbage collect MessagePorts when they can be passed between
> processes.
>

Would you consider this an implementation-blocking problem?

By the way, another option is to remove the ability to block, so it always
behaves as getMessage(0)--return a waiting message, but don't wait for
one.  That would also make it impossible to deadlock.  Being able to wait
for a message would be a nice plus, but I don't think I've seen any use
cases that really require it.  (If this is done, there's no need to be able
to give multiple ports to getMessage, as I mentioned at the top, since you
can just call getMessage separately for each port.)

-- 
Glenn Maynard

Received on Sunday, 2 September 2012 19:16:58 UTC