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
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