Did you know? DZone has great portals for Python, Cloud, NoSQL, and HTML5!
HTML5 Zone is brought to you in partnership with:

Sasha Goldshtein is a Senior Consultant for Sela Group, an Israeli company specializing in training, consulting and outsourcing to local and international customers.Sasha's work is divided across these three primary disciplines. He consults for clients on architecture, development, debugging and performance issues; he actively develops code using the latest bits of technology from Microsoft; and he conducts training classes on a variety of topics, from Windows Internals to .NET Performance. You can read more about Sasha's work and his latest ventures at his blog: http://blogs.microsoft.co.il/blogs/sasha. Sasha writes from Herzliya, Israel. Sasha is a DZone MVB and is not an employee of DZone and has posted 114 posts at DZone. You can read more from them at their website. View Full User Profile

HTML5 Web Workers: Classic Message Passing Concurrency

02.06.2012
Email
Views: 2565
  • submit to reddit
The HTML5 Microzone is presented by DZone and Microsoft to bring you the most interesting and relevant content on emerging web standards.  Experience all that the HTML5 Microzone has to offer on our homepage and check out the cutting edge web development tutorials on Script Junkie, Build My Pinned Site, and the HTML5 DevCenter.

Most concurrency frameworks I write about on this blog consist of numerous layers of abstraction. Consider the Task Parallel Library, for instance: it’s a wrapper on top of the .NET Thread Pool, which is a wrapper on top of Windows threads. This cruft of low-level abstraction layers forces certain expectations from the newer libraries – namely, they must allow direct access to shared state, provide synchronization mechanisms, volatile variables, atomic synchronization primitives, …

It seems that JavaScript (HTML5) with its Web Workers standard enjoys the lack of abstraction cruft for threading in the JavaScript world. Because there are no underlying low-level libraries for multithreaded JavaScript computation (in the browser), Web Workers are free to reinvent not only the APIs, but also the concurrency style.

Web Workers provide a message-passing model, where scripts can communicate only through well-defined immutable messages, do not share any data, and do not use synchronization mechanisms for signaling or data integrity. Indeed, Web Workers are not ridden with classic concurrency problems such as deadlocks and race conditions – simply because these concurrency problems are impossible.

Frankly, I’m a little jealous of JavaScript developers who can now leverage multithreading in their browser-side applications. The Web Workers API is minimalistic but done right. Below is a small example of a multithreaded prime number search with Web Workers – if you are looking for a more detailed introduction and walkthrough, check out the following resources:

First, the UI:

<input type="text" id="range_start"
       placeholder="start (e.g. 2)" /><br/>
<input type="text" id="range_end"
       placeholder="end (e.g. 100000)" /><br/>
<label for="dop">Degree of parallelism:</label>
<input type="range" id="dop"
       min="1" max="8" value="4" step="1" /><br/>
<input type="button" id="calculate" value="Calculate" />

image

Now the actual business. When the “Calculate” button is clicked, we spawn the specified number of worker threads to do the calculation in the background. The main thread passes to the workers the range of primes they will work on, and receives from the workers progress reports and the final count:

//Some parts of the code elided for clarity
$(document).ready(function () {
    $("#calculate").click(function (e) {
        e.preventDefault();
        var rangeStart = parseInt($("#range_start").val());
        var rangeEnd = parseInt($("#range_end").val());
        var parallelism = parseInt($("#dop").val());
        createWorkers(parallelism, rangeStart, rangeEnd);
    });
});
function createWorkers(parallelism, start, end) {
    var range = end - start;
    var chunk = range / parallelism;
    var count = 0;
    var done = 0;
    for (var i = 0; i < parallelism; ++i) {
        var worker = new Worker("prime_finder.js");
        worker.onmessage = function(event) {
            if (event.data.type === 'DONE') {
                ++done;
                count += event.data.count;
                if (done == parallelism) ...
            } else if (event.data.type === 'PROGRESS') {
                var progress = event.data.value;
                ...
            }
        };
        var init = {
            start: start + i*chunk,
            end: start + (i+1)*chunk,
            idx: i
        };
        worker.postMessage(init);
    }
}

Note the communication between the threads. The main thread uses Worker.postMessage to provide data to the worker thread, and receives from it status updates using the onmessage event. The worker thread runs the prime_finder.js script:

//The isPrime function elided for brevity
self.onmessage = function (event) {
    var start = event.data.start;
    var end = event.data.end;
    var size = end - start;
    var count = 0;
    for (var i = start; i < end; ++i) {
        if (isPrime(i)) ++count;
        if (i % 1000 === 0) {
            self.postMessage({
                type: 'PROGRESS',
                value: 100.0*((i-start)/size),
                idx: event.data.idx
            });
        }
    }
    self.postMessage({
        type: 'DONE',
        count: count,
        idx: event.data.idx
    });
};

Here we see the opposite direction – the worker thread periodically posts progress reports and eventually reports completion. The whole thing is triggered by the receipt of the initial message from the main thread.

image
(In this screenshot you can see how uneven the distribution of work turns out to be – the first thread finishes very quickly while the fourth thread lags behind quite slowly…)

To experiment with this code, you can download the full demo, including a very small Node.js server that serves it.

If you have a C# or C++ development background, it all probably feels very unnatural to you. Where is the shared state? Where are the synchronization mechanisms? Where are the function pointers? – Indeed, it can be scary to write a multithreaded program using only asynchronous message passing – but it’s a much cleaner start than many of the libraries we have today.

 

Source: http://blogs.microsoft.co.il/blogs/sasha/archive/2012/02/05/html5-web-workers-classic-message-passing-concurrency.aspx

Published at DZone with permission of Sasha Goldshtein, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

HTML5 is the most dramatic step in the evolution of web standards. It incorporates features such as geolocation, video playback and drag-and-drop. HTML5 allows developers to create rich internet applications without the need for third party APIs and browser plug-ins.  Under the banner of HTML5, modern web standards such as CSS3, SVG, XHR2, WebSockets, IndexedDB, and AppCache are pushing the boundaries for what a browser can achieve using web standards.  This Microzone is supported by Microsoft, and it will delve into the intricacies of using these new web technologies and teach you how to make your websites compatible with all of the modern browsers.