Wednesday, December 19, 2007

Threading in JavaScript 1.7

Found this only today...

---------------------------

Amongst the many new features contained in Firefox 2 you’ll find JavaScript 1.7 support, a small but significant language enhancement that includes python style generators.

A generator allows you to suspend a function’s execution and resume it at a later time. While typically used for advanced looping constructs, a generator can also be flipped inside-out and used as a rudimentary coroutine.

At first glance, this may not look very impressive, especially since generators are unable to yield across multiple frames in the callstack. However, with the help of a technique called trampolining generators can be used to write code in a style similar to threaded programming.

The way trampolining works is that a scheduler object (written in JavaScript) manages the execution of a series of generators, cobbling together a stack-like execution. Here’s how it works: The scheduler sets the starting generator as the base “frame” in the call stack. The scheduler then calls next() on the generator to obtain a yield value. If the yielded value is itself a generator, the scheduler pushes this new generator on the stack and calls next() on it, again obtaining a yield value. This continues until the top generator yields a non-generator value. This value could be a special directive to the scheduler (for example, a SUSPEND value that tells the scheduler to freeze execution of the “stack” of generators we’ve piled up). If not, the scheduler treats it as a return value. The scheduler then pops and closes the now complete generator and sends the return value back into the next generator in the stack.

Sound confusing? It’s a mind-bender — I had to read a trampolining description and its sample code a few times before I understood how it works.

The coding style when trampolining is a little awkward. You need to yield any function call that will suspend execution of the stack. Here’s a contrived example:

  function myThreadedCall() {
while (!ready) {
yield sleep(100);
}
yield waitForInput();
if ((yield post(getInput())) != null ) {
yield animateUI();
}
}

In this way, using generators to trampoline is a very explicit form of concurrency. It’s verbose (unlike, say, Lua-style coroutines), but that verbosity has the upside of execution clarity — it’s much easier to see on visual inspection where race conditions can occur.

(Those of you with sharp eyes will notice that the technique described here is not true threading, but fancy coroutines. That’s the underlying implementation; to the programmer using this technique, it looks a lot like threading.)

No discussion like this would be complete without a pointless example, and this post is no exception. Check out this example (only works in Firefox 2), along with the example source and the threading library.

The use of generators and trampoling isn’t a panacea for concurrency in JavaScript. The technique renders code essentially “stackless” as far as the JavaScript interpreter is concerned, which means that you won’t get a meaningful stack trace if an error occurs. Thus debugging can be a bit painful.

However, it’s worth noting that the trampolining Thread.js is a slim 4K (uncompressed). And there’s no pre-compilation, no parsing, no AST manipulation, and no code generation. Simple. That’s the benefit of native language features.

All in all, I wish JavaScript had a more directly supported concurrency mechanism. I raised the topic on the ES4/JavaScript 2 discussion list, but in the end it was decided that the inability to yield through native C stack frames at the implementation level made it infeasible for some embeddings (such as cell phones and other devices). We’ll see what happens in later versions. (Brendan Eich has hinted that JS3 will be ready for multicore desktops.)


source: http://www.neilmix.com/2007/02/07/threading-in-javascript-17/

No comments:

Blogger Panel