Tuesday, October 26th, 2010

Adding fibers to your server side v8 diet offers efficiency and clarity

Category: JavaScript, Library

<blockquote>

In computer science, a fiber is a particularly lightweight thread of execution.

Like threads, fibers share address space. However, fibers use co-operative multitasking while threads use pre-emptive multitasking. Threads often depend on the kernel’s thread scheduler to preempt a busy thread and resume another thread; fibers yield themselves to run another fiber while executing. The article on threads contains more on the distinction between threads and fibers.

Fibers describe essentially the same concept as coroutines. The distinction, if there is any, is that coroutines are a language-level construct, a form of control flow, while fibers are a systems-level construct, viewed as threads that happen not to run concurrently. Priority is contentious; fibers may be viewed as an implementation of coroutines, or as a substrate on which to implement coroutines.

The above is taken from Wikipedia, which is discussing the computer science concepts behind fibers.

Why do we bring this up? The Asana team (who we featured when they came out with LunaScript) continue their quest to make an ergonomic, productive, and performant framework for the Web.

Today they are discussing their patch to v8cgi that adds in support for their own fiber implementation.

It all ends up with this:

Few languages support fibers natively (though support was recently added to Ruby). We write most of our server code in JavaScript and run it under Google’s v8 engine, the same JS runtime that Chrome uses. Fortunately the v8 codebase is excellently structured, so we were able to add fiber support in just a few days. Our changes take the form of a patch (currently pending review) to v8cgi, a library of server-oriented extensions to v8.

Here’s a sample of the API:

javascript
< view plain text >
  1. // Make a new fiber. The fiber will run the provided function.
  2. var fiber = new Fiber('name', function() {
  3.  
  4.   // ...
  5.  
  6.   // Make another fiber runnable.
  7.   some_other_fiber.becomeRunnable();
  8.  
  9.   // Suspend the current one.
  10.   Fiber.current.suspend();
  11.  
  12.   // ...
  13. });
  14.  
  15. // Make the new fiber runnable. It won't start until the current fiber suspends
  16. // or joins.
  17. fiber.becomeRunnable();
  18.  
  19. // Wait for the fiber to finish.
  20. fiber.join();

That’s almost the entire API. We don’t need any synchronization primitives because only one fiber runs at a time and control only changes when suspend() or join() is called.

There is a tension between writing clear, well-abstracted code and writing code that makes efficient use of the database. Adding fibers to v8 allowed us to resolve this tension. In taking a small amount of time to solve this problem “right” up front, we’ve made our entire engineering team more efficient for the long run.

Read the post to get the background, and to see the refactoring that is done to get to this place.

Asana seems to be really enjoying rethinking the world of Web frameworks. I can’t wait to see their products!

name lookup timed out

Posted by Dion Almaer at 11:03 am
4 Comments

++++-
4 rating from 9 votes

4 Comments »

Comments feed TrackBack URI

Interesting – reminds me of Stratified Javascript http://ajaxian.com/archives/stratified-javascript-concurrency-features-in-javascript / http://stratifiedjs.org/ — is there a trend here?

Comment by danbri — October 26, 2010

I currently fire a request to localhost or 127.0.0.1 with Ajax, and put execution code of worker in callback. In that case I can trigger 100 threads easily.

Comment by rebecca20 — November 3, 2010

@rebecca20: Ajax calls should not be used for deferring/scheduling tasks, except for tasks that must wait for a server’s response. In your case, what you’re doing would be much better accomplished using successive calls to setTimeout — either way, Javascript is single-threaded and will execute the “threads” one by one.
.
Unless you have a good reason for delaying tasks (like running a large task in pieces so as to not block user interaction), you’re better off just running all your code sequentially. Javascript is not multi-threaded, but it does provide great performance for single-threaded routines that utilize setTimeout and callbacks to enable user interaction during long-running tasks or during calls to the server.
.
In the case of the above post, fibers are being utilized on server-side Javascript to boost performance when dealing with concurrent IO-handling tasks (“fibers”), probably in the context of Node.js or a similar setup.

Comment by pianoroy — November 8, 2010

There may be reason for two different .suspend functions: one which resumes execution within the current event loop, and one which waits for the next event loop.

-charles

Comment by Downchuck — November 24, 2010

Leave a comment

You must be logged in to post a comment.