Re: Sync API for workers

My reading (from the proposed APIs) is that these are only synchronous from the Worker's PoV.  If that's correct I have no real objections to such an API - the render thread simply sees a regular message.  It doesn't even need a special API on the receiving side.  If the Worker has

...
var response = postSynchronousMessage(message)
...

and the renderer has

worker.onmessage =function() { ....; return "foo" }

There are no UI blocking hazards (other than the usual slow event handler problem, which is already present anyway)

The only real problem I can see is along the lines of:

// Worker1
onmessage = function () { ...worker2.postSynchronousMessage(...)... }

// Worker2
onmessage = function () { ...worker1.postSynchronousMessage(...)... }

In the current implementations I imagine that this may cause difficulty, but I don't think that there is an actual technical argument against it.

--Oliver


On Sep 1, 2012, at 1:38 PM, Rick Waldron wrote:

> 
> 
> On Saturday, September 1, 2012 at 4:28 PM, Olli Pettay wrote:
> 
>> On 09/01/2012 11:19 PM, Rick Waldron wrote:
>>> 
>>> David,
>>> 
>>> Thanks for preparing this summary—I just wanted to note that I still stand behind my original, reality based arguments.
>>> 
>>> One comment inline..
>>> 
>>> On Saturday, September 1, 2012 at 12:49 PM, David Bruant wrote:
>>> 
>>>> Hi,
>>>> 
>>>> A Sync API for workers is being implemented in Firefox [1].
>>>> I'd like to come back to the discussions mentionned in comment 4 of the bug.
>>> The original post actually describes an async API—putting the word "sync" in the middle of a method or event name doesn't make it "sync".
>>> 
>>> As the proposed API developed, it still retains the "event handler"-esque design (https://bugzilla.mozilla.org/show_bug.cgi?id=783190#c12). All of the
>>> terminology being used is "async":
>>> - event
>>> - callback
>>> - "onfoo"
>>> 
>>> Even Olli's proposal example is async. https://bugzilla.mozilla.org/show_bug.cgi?id=783190#c9 (setTimeout)
>>> 
>>> If the argument is "callback hell", save it—because if that's the problem with your program, then your doing it wrong (see: node.js ecosystem).
>>> 
>>> 
>>> If this API introduces any renderer process blocking, the result will be catastrophic in the hands of inexperienced web developers.
>> 
>> 
>> I haven't seen any proposal which would block rendering/main/dom thread
> So far, they all look async. Just calling them "sync" doesn't make them "sync". A sync worker API:
> 
> // really sync behaviour means blocking until this returns: 
> var result = rendererBlockingAPI( data );
> 
> Unless you specifically design that to stop everything and wait for a response (renderer blocking), JavaScript will "run to completion".
> 
> Rick
>  
>  
>> 
>> 
>> We've been thinking the following approaches:
>> 
>> Proposal 1
>> Parent Thread:
>> var w = new Worker('foo.js');
>> w.onsyncmessage = function(event) {
>> event.reply('bar');
>> }
>> Worker:
>> var r = postSyncMessage('foobar', null, 1000 /* timeout */);
>> if (r == 'bar') ..
>> PRO:
>> - It's already implemented :)
>> CON:
>> - Multiple event listeners - Multiple reply() calls. How to deal with it?
>> - Multiple event listeners - is this your message?
>> - Wrong order of the messages in worker if parent sends async message just before receiving sync message
>> - The message must be read in order to reply
>> 
>> 
>> Proposal 1.1
>> Parent Thread:
>> var w = new Worker('foo.js');
>> w.onsyncmessage = function(event) {
>> var r = new Reply(event);
>> r.reply("bar"); // Can be called after event dispatch.
>> }
>> Worker:
>> var replies = postSyncMessage('foobar', null, 1000 /* timeout */);
>> for (var r in replies) {
>> handleEachReply(r);
>> }
>> PRO:
>> - Can handle multiple replies.
>> - No awkward limitations on main thread because of reply handling
>> CON:
>> - A bit ugly.
>> - Reply on the worker thread becomes an array - unintuitive
>> - Wrong order of the messages in worker if parent sends async message just before receiving sync message
>> - The Reply object must be created during event dispatch.
>> 
>> 
>> Proposal 2
>> Parent Thread:
>> var w = new Worker('foo.js');
>> w.setSyncHandler('typeFoobar', function(message) {
>> return 'bar';
>> });
>> Worker:
>> var r = postSyncMessage('typeFoobar', 'foobar', null, 1000 /* timeout */);
>> if (r == 'bar') ..
>> PRO:
>> - no multple replyies are possible
>> - types for sync messages
>> CON:
>> - Just a "single listener"
>> - It's not based on event - it's something different compare with any other worker/parent communication.
>> - Wrong order of the messages in worker if parent sends async message just before receiving sync message
>> 
>> 
>> Proposal 3
>> Worker:
>> postMessage("I want reply to this");
>> var events = [];
>> while (var m = waitForMessage()) {
>> if (m.data != /* the reply * /) {
>> events.push(m);
>> } else {
>> // do something with message
>> }
>> }
>> while (events.length()) {
>> dispatchEvent(events.shift());
>> }
>> PRO:
>> - Flexible
>> - the order of the events is changed by the developer
>> - since there isn't any special sync messaging, multiple event listeners don't
>> cause problems.
>> CON:
>> - complex for web developers(?)
>> - The message must be read in order to reply
>> - Means that you can't use libraries that use sync messages. Only frameworks are possible as all message handling needs to be aware of the new
>> syncmessages.
>> 
>> 
>> 
>> 
>> Atm, I personally prefer the proposal 3.
>> 
>> 
>> -Olli
>> 
>> 
>>> 
>>> 
>>> Rick
>>>> 
>>>> A summary of points I find important and my comments, questions and concerns
>>>> 
>>>> # Discussion 1
>>>> ## Glenn Maynard [2] Use case exposed:
>>>> Ability to cancel long-running synchronous worker task
>>>> "Terminating the whole worker thread is the blunt way to do it; that's
>>>> no good since it requires starting a new thread for every keystroke, and
>>>> there may be significant startup costs (eg. loading search data)."
>>>> => It's a legitimate use case that has no good solution today other than
>>>> cutting the task in smaller tasks between which a cancellation message
>>>> can be interleaved.
>>>> 
>>>> 
>>>> ## Tab Atkins [3]
>>>> "If we were to fix this, it needs to be done at the language level,
>>>> because there are language-level issues to be solved that can't be
>>>> hacked around by a specialized solution."
>>>> => I agree a lot with that point. This is a discussion that should be
>>>> had on es-discuss since JavaScript is the underlying language.
>>>> ECMAScript per se doesn't define a concurrency model and it's not even
>>>> on the table for ES.next, but might be in ES.next.next (7?). See [concurr]
>>>> 
>>>> ## Jonas Sicking [4]
>>>> Ideas of providing control (read-only) over pending messages in workers.
>>>> (not part of the current Sync API, but interesting nonetheless)
>>>> 
>>>> 
>>>> 
>>>> # Discussion 2
>>>> ## Joshua Bell [5]
>>>> "This can be done today using bidirectional postMessage, but of course
>>>> this requires the Worker to then be coded in now common asynchronous
>>>> JavaScript fashion, with either a tangled mess of callbacks or some sort
>>>> of Promises/Futures library, which removes some of the benefits of
>>>> introducing sync APIs to Workers in the first place."
>>>> => What are these benefits? Is the cost of the Promises/Future library
>>>> so high it
>>>> Back to Tab's point of the previous discussion, this is a language
>>>> issue, not an API issue. It ought to be solved at the language level
>>>> 
>>>> 
>>>> ## Rick Waldron [6]
>>>> "This is counter to the whole premise of Workers, which should be
>>>> independent of their renderer process and certainly not block themselves
>>>> while waiting for responses from the renderer (which inherently
>>>> describes an async behaviour)."
>>>> => Indeed. Having a blocked worker makes that when you need other tasks
>>>> to happen in parallel, you need to spawn new workers which is a waste of
>>>> resources, very much like Apache which opens a new thread for each HTTP
>>>> connection while some thread are idling (I don't know if it's still the
>>>> case, but it used to)
>>>> 
>>>> 
>>>> ## Glenn Maynard [7]
>>>> "I think this is a fundamental missing piece to worker communication. A
>>>> basic reason for having Workers in the first place is so you can write
>>>> linear code, instead of having to structure code to be able to return
>>>> regularly (often awkward and inconvenient), but currently in order to
>>>> receive messages in workers you still have to do that."
>>>> => A basic reason for having workers is to move computation away from
>>>> window to a concurrent and parallel computation unit so that the UI is
>>>> not blocked by computation. End of story. Nothing to do with writing
>>>> linear code. If JavaScript as it is doesn't allow people to write code
>>>> as they wish, once again, it's a language issue. Either ask a change in
>>>> the language or create a language that looks the way you want and
>>>> compiles down to JavaScript.
>>>> 
>>>> 
>>>> 
>>>> I wish to add that adding a sync API (even if the sync aspect is
>>>> asymetrical as proposed in [1]) breaks the event-loop run-to-completion
>>>> model of in-browser-JavaScript which is intended to be formalized at
>>>> [concurr]. This model is what prevents web pages from ever freezing from
>>>> a deadlock. The proposed API preserves this, but create the threat of
>>>> deadlocks for workers.
>>>> 
>>>> Besides programmer convenience, few arguments have been advanced to
>>>> justify the breakage of the current concurrency model (I don't even
>>>> think the breakage has been mentionned at all!). And as said several
>>>> times, programmer convenience are more of a language issue than an API
>>>> issue for the specific things we're talking about.
>>>> Also, I don't think I have seen mentionned use cases of things that are
>>>> not possible without a Sync API. Everything presented is already
>>>> possible (sometimes at arguably high costs like Glenn Maynard's use case
>>>> in discussion [1]).
>>>> 
>>>> David
>>>> 
>>>> [1] https://bugzilla.mozilla.org/show_bug.cgi?id=783190
>>>> [2] http://lists.w3.org/Archives/Public/public-webapps/2010OctDec/1075.html
>>>> [3] http://lists.w3.org/Archives/Public/public-webapps/2010OctDec/1082.html
>>>> [4] http://lists.w3.org/Archives/Public/public-webapps/2010OctDec/1086.html
>>>> [5] http://lists.w3.org/Archives/Public/public-webapps/2011OctDec/0965.html
>>>> [6] http://lists.w3.org/Archives/Public/public-webapps/2011OctDec/0966.html
>>>> [7] http://lists.w3.org/Archives/Public/public-webapps/2011OctDec/0967.html
>>>> [concurr] http://wiki.ecmascript.org/doku.php?id=strawman:concurrency
> 

Received on Saturday, 1 September 2012 20:52:29 UTC