Re: Sync API for workers

On Wed, Sep 5, 2012 at 11:30 PM, Olli Pettay <Olli.Pettay@helsinki.fi> wrote:
> On 09/06/2012 09:12 AM, Jonas Sicking wrote:
>>
>> On Wed, Sep 5, 2012 at 11:02 PM, bugs@pettay.fi <bugs@pettay.fi> wrote:
>>>
>>> On 09/06/2012 08:31 AM, Jonas Sicking wrote:
>>>>
>>>>
>>>> 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).
>>>
>>>
>>> It is just dispatching events.
>>> The problems we (Gecko) have had with event loop spinning in main thread
>>> relate mainly to the problems where "unexpected" events are dispatched
>>> while
>>> running the loop, as an example user input events or events coming from
>>> network.
>>> getMessage/waitForMessage does not have that problem.
>>
>>
>> I'm not sure what you mean by "just dispatching events". That's
>> exactly what event loop spinning is.
>
>
> No. waitForMessage example I wrote down just dispatches DOM events in a
> loop.
> That is a synchronous operation and you know exactly which events you're
> about to dispatch.
> If you run the generic event loop, you also end up running
> timers and getting input from network and user etc. and you can't
> controls those.

Just because they are message events doesn't mean that "you know
exactly which events you're about to dispatch". That's basically
equivalent to saying that it's safe to spin the event loop in Gecko as
long as you only dispatch nsIRunnables that were dispatched from Gecko
code, as opposed to native events from the native event loop.

Note that messages can be sent to the worker in response to network
and UI events on the main thread.

>> Why are the gecko events any more "unexpected" than the message events
>> that the example dispatches.
>
> We don't want to block certain events in Gecko (like user input to chrome).
> Blocking events in worker code is ok.

I don't understand what you are saying here.

>> If they at that point call into a library which
>> starts pulling messages off of the task queue and dispatches them,
>> they'll run into the same problems as we've had.
>
> ...but then it is up to the library to handle the case properly and
> dispatch events async.

But if it dispatches them asynchronously, they have lost their place
in the message queue. I.e. now they are placed after all other
incoming message events. Such event reordering is likely to break
application level logic.

And like I said in my original email, you can fix that reordering by
completely redoing all you message event handling and using a
framework. But I'd like to find a solution that doesn't require that.
Especially since that still wouldn't fix the fact that messages get
reordered compared to other types of tasks on the task queue.

> Though, dispatching events async so that other new message events don't get
> handled before them
> would require some new API.

Exactly. And you'd have to make sure that they get dispatched in the
correct order compared to the other events that you are pulling out
using waitForMessage. I.e. simply an API which inserts them in the
beginning of the task queue wouldn't be enough. You'd need something
like an iterator which lets you iterate the task queue and inspect
messages and only pull out selected ones. And allow that iterator to
block once it sees no more incoming messages.

But that is a whole lot messier than the other proposals that have
been discussed. And what you would effectively have is something that
amounts to a separate communication channel which you can pull
messages out of while ignoring all other pending messages in other
channels. So why not simply use an actual separate channel instead?

That is what proposal 1 and 2 effectively does. As does the proposals
from Glenn and me.

/ Jonas

Received on Thursday, 6 September 2012 06:50:48 UTC