MSDN Magazine - October 2008 - (Page 75) Another familiar form of concurrency applies to server applications. Applications such as Web servers are presented streams of independent requests. These programs attempt to improve system throughput by executing many requests at the same time, typically using a separate thread for each request but then sequentially processing each request. This overlapping increases requests served per second but does not improve the latency (seconds per request) of individual requests. These applications have also been enjoying a free lunch, one that will continue a bit longer as multicore processing provides additional cost reduction and throughput benefits. However, any request that is sensitive to latency, even in a server environment, will eventually need to use parallel programming techniques to achieve acceptable performance. Concurrent programming is notoriously difficult, even for experts. When logically independent requests share various resources (dictionaries, buffer pools, database connections, and so forth), the programmer must orchestrate the sharing, introducing new problems. These problems—data races, deadlocks, livelocks, and so forth—generally derive from a variety of uncertainties that arise when concurrent tasks attempt to manipulate the same data objects in a program. These problems make the basic software development tasks of testing and debugging extremely difficult, as recently outlined in “Tools and Techniques to Identify Concurrency Issues” by Rahul Patil and Boby George (MSDN Magazine, June 2008, msdn.microsoft.com/magazine/cc546569). Parallel programming differs from concurrent programming in that you must take what is logically a single task—expressible using familiar sequential constructs supported by all major languages— and introduce opportunities for concurrent execution. (Later in this article, I will describe broad approaches to such opportunities.) However, when concurrency opportunities are introduced with subtasks that share data objects, you have to worry about locking and races. Thus, parallel programming has all of the correctness and security challenges of sequential programs plus all of the difficulties of parallelism and concurrent access to shared resources. The combination of extra concepts, new failure modes, and testing difficulty should give every developer pause. Is this something you really want to bite off? Clearly, the answer is no! However, many will be forced into this swamp in order to deliver the necessary performance. Microsoft is actively developing solutions to some of the core problems, but high-productivity solution stacks are not yet available. Last year, Microsoft announced its Parallel Computing Initiative (go.microsoft.com/fwlink/?LinkId=124050) to look at not only how to build and efficiently execute parallel programs but also to encourage creation of a new generation of applications that turn Moore’s Dividend into customer value. I will soon examine some approaches to thinking about parallelism. Stephen Toub and Hazim Shafi’s article in this issue, “Improved Support for Parallelism in the Next Vermsdnmagazine.com If you want a return of the free lunch where software gets better, you need to provide the opportunity for more parallelism today in ways that can be used tomorrow. sion of Visual Studio,” describes some of the libraries and tools that we are providing to support these approaches (see msdn.microsoft.com/magazine/cc817396). Joe Duffy’s article, “Solving 11 Likely Problems in Your Multithreaded Code” (msdn.microsoft.com/magazine/cc817398), also in this issue, discusses techniques and approaches to improving the safety of concurrent applications. Previously, I used the phrase “opportunities for concurrent execution,” which draws a further distinction between parallel and concurrent programming. When a developer uses asynchronous programming patterns or background workers, or handles concurrent requests in a server, there is an expectation that all the various threads make forward progress. The operating system scheduler will make sure every thread gets a fair share of resources. This, however, is not useful for parallel programming. It is particularly not valuable when you are interested in writing applications that will scale to new hardware systems. If you want a return of the free lunch where software just gets better with hardware upgrades, then you need to provide the opportunity for more parallelism today in ways that can be used tomorrow. Here I will use the term “tasks” rather than “threads” to emphasize this shift in the implementation of parallelism and how I think about it: developers that tackle parallel programming will be encouraged to decompose problems into many more tasks than are needed today. The implementation of parallel programming systems will need to deal with mapping those tasks onto system threads and processors on an as-needed basis. Visible to only a few programmers, there are deep changes in the way in which system resources are acquired from the operating system and managed within a process to execute parallel programs efficiently. This is like a thread pool on steroids, but one that is focused on matching opportunities for parallelism in an application to the available resources in the current hardware rather than simply managing threads as specified by the parallel programmer. In concurrent programming, especially for servers, much of the difficulty arises from coordinating accesses to shared variables by long-running threads using tools such as locks. As we shift to parallel programming with tasks, a new concept can be used. I can talk about a task B running after a task A and provide coordination primitives to express this. This allows a programmer to think about the schedule of work. Typically this schedule will fit naturally into the algorithmic structure of the program and emerge from structured use of parallel programming abstractions. Good fits between program abstractions and parallel algorithms will greatly reduce the need for traditional concurrency mechanisms, such as locks and events, and avoid, but not eliminate, many of the risks of concurrent programming. Next, I’ll describe some major approaches to parallel programming and illustrate their use through abstractions that are under October 2008 75 http://msdn.microsoft.com/magazine/cc817396 http://msdn.microsoft.com/magazine/cc817398 http://msdn.microsoft.com/magazine/cc817398 http://msdn.microsoft.com/magazine/cc546569 http://go.microsoft.com/fwlink/?LinkId=124050 http://www.msdnmagazine.com
For optimal viewing of this digital publication, please enable JavaScript and then refresh the page. If you would like to try to load the digital publication without using Flash Player detection, please click here.