Introduction to HTML5 Web Workers: Use Cases and Identify Hot Spots
written by David Rousset
Previously we introduced HTML5 Web Workers, showed you how to post messages using JSON, and discussed web browsers support, non-accessible elements, and error handling & debugging. This week we will look at use cases and specific scenarios for the use of Web Workers, and will show you how to locate hot spots within your code.
Use Cases and How to Identify Potential Candidates
Web Workers for Which Scenarios?
It's true that the limitations we've seen above on the resources available inside Web Workers narrow down the number of interesting scenarios. Still, if you just take some time to think about it, you'll start to see new interesting usages:
- image processing by using the data extracted from the <canvas> or the <video> elements. You can divide the image into several zones and push them to the different Workers that will work in parallel. You'll then benefit from the new generation of multi-cores CPUs. The more you have, the faster you'll go.
- big amount of data retrieved that you need to parse after an XMLHTTPRequest call. If the time needed to process this data is important, you'd better do it in background inside a Web Worker to avoid freezing the UI Thread. You'll then keep a reactive application.
- concurrent requests against a local database. IndexDB will allow what the Local Storage can't offer us: a thread-safe storage environment for our Web Workers.
Moreover, if you switch to the video game world, you can think about pushing the AI or physics engines to the Web Workers. For instance, I've found this experimentation: On Web Workers, GWT, and a New Physics Demo which use the Box2D physic engine with Workers. For your Artificial Intelligence engine, this means also that you will be able in the same timeframe to process more data (anticipate more moves in a chess game for instance).
Some of my colleagues may now argue that the only limit is your imagination!
- The initializing time and the communication time with the worker shouldn't be superior to the processing itself
- The memory cost of using several Workers
- The dependency of the code blocks between them as you may then need some synchronization logic. Parallelization is not something easy my friends!
On our side, we've recently published the demo named Web Workers Fountains:
This demo displays some particles effects (the fountains) and uses 1 Web Worker per fountain to try to compute the particles in the fastest way possible. Each Worker result is then aggregated to be displayed inside the <canvas> element. Web Workers can also exchange messages between them via the Message Channels. In this demo, this is used to ask to each of the Workers when to change the color of the fountains. We're then looping through this array of colors: red, orange, yellow, green, blue, purple, and pink, thanks to the Message Channels. If you're interested in the details, jump into the LightManager() function of the Demo3.js file.
Also, feel free to launch this demo inside Internet Explorer 10, it's fun to play with!
How To Identify Hot Spots in Your Code
To track the bottlenecks and identify which parts of your code you could send to the Web Workers, you can use the script profiler available with the F12 bar of IE9/10. It will then help you to identify your hot spots. However, identifying a hot spot doesn't mean you've identified a good candidate for Web Workers. To better understand that, let's review together two different interesting cases.
Case 1: Animation inside <canvas> with the Speed Reading demo
This demo comes from IE Test Drive and can be browsed directly here: Speed Reading. It tries to display some characters as fast as possible using the <canvas> element. The goal is to stress the quality of the implementation of the hardware acceleration layer of your browser. But going beyond that, would it be possible to obtain more performance by splitting some operations on threads? We need to achieve some analysis to check that.
If you run this demo inside IE9/10, you can also start the profiler within a couple of seconds. Here is the kind of results you'll obtain:
If you're sorting the time-consuming functions in decreasing order, you'll clearly see those functions coming first: DrawLoop(), Draw() and drawImage(). If you're double-clicking on the Draw line, you'll jump into the code of this method. You'll then observe several calls of this type:
surface.drawImage(imgTile, 0, 0, 70, 100, this.left, this.top, this.width, this.height);
Where the surface object is referencing a <canvas> element.
A quick conclusion of this brief analysis is that this demo spends most of its time drawing inside the Canvas through the drawImage() method. As the <canvas> element is not accessible from a Web Worker, we won't be able to offload this time-consuming task to different threads (we could have imagined some ways of handling the <canvas> element in a concurrency manner for instance). This demo is then not a good candidate for the parallelization possibilities offered by the Web Workers.
It's well-illustrating the process you need to put in place, however. If, after a profiling job, you're discovering that the major part of the time-consuming scripts are deeply linked to DOM objects, the Web Workers won't be able to help you boost the performance of your Web app.
Case 2: Raytracers inside <canvas>
Let's now take another easy example to understand. Let's take a raytracer like this one: Flog.RayTracer Canvas Demo. A raytracer uses some very CPU-intensive mathematical computations in order to simulate the path of light. The idea is to simulate some effects like reflection, refraction, materials, etc.
Let's render a scene while launching the script profiler. You should obtain something like this:
Again, if we sort the functions in decreasing order, 2 functions clearly seem to take most of the time: renderScene() and getPixelColor().
This is then not a surprise if we can find some raytracers samples using some Web Workers like this one.
After profiling this raytracer using IE10, we can see the important differences between using no Worker and using 4 Workers:
In the first screenshot, the processRenderCommand() method is using almost all of the CPU available and the scene is rendered in 2.854s.
With 4 Web Workers, the processRenderCommand() method is executed in parallel on 4 different threads. We can even see their Worker Id on the right column. The scene is rendered this time in 1.473s. The benefits were real: the scene has been rendered 2 times faster.
Additional Web Worker Resources
Here are some interesting additional resources to read:
About the Author
This article was reprinted with permission from Microsoft Corporation. This site does business with Microsoft Corporation.