UNPKG

ems

Version:

Persistent Shared Memory and Parallel Programming Model

148 lines (107 loc) 6.35 kB
# Parallelism Generating a Single HTTP Response Using Fork-Join (FJ) parallelism a conventional HTTP server can use multiple cores to generate a single a response by forking threads when a request is received, generating the response in parallel, joining all the threads when the work is complete, and then returning the response from the original single thread. HTTP applications frequently require state to persist between requests, this example uses the URL path as a session ID that can be used to persist state between requests. Each request itself may include one or more fork-join parallel regions. ## Parallel Web Server Architecture This example combines Node.js' built-in HTTP server module with EMS for shared memory and task level parallelism. When the server is started it allocates a globally shared EMS shared memory (`serverState.ems`) that exists until the server exits. The global shared memory is used for diagnostic counters like the number of queries as well as key-value pairs that can be read or written from a parallel or serial region of any request or session. <img src="http://synsem.com/images/ems/parWebServer.svg" type="image/svg+xml"> ## REST API A valid request URL consists of path naming the session ID and a query that specifies if the session is new/restarting, or is a continuation of a previous session. __REST API:__ `/sessionID?<old|new>&<keep|free>` - `sessionID` - An unique session identifier. The shared memory persistent file will be named `session.sessionID.ems` and stored in the current working directory. - `?<old|new>` - A `new` session will remove an existing session-private shared memory if present, an `old` session will attach to a previously created shared memory that was persisted to disk. - `?<keep|free>` - Release or preserve, respectively, the session's shared memory at the end of the request. ## Fork-Join Parallelism A process using Fork-Join parallelism starts single-threaded, creating parallel regions when needed, then returning to single-threaded execution when all the threads in the parallel region have completed execution. EMS amortizes the cost of starting new processes by using a thread pool where idle threads can quickly be restarted when they are needed again. By way of comparison, all the processes in Bulk Synchronous Parallelism are always executing, barriers can be used to synchronize execution. <table> <tr> <td> <center> Fork-Join Parallelism<br> <img src="http://synsem.com/images/ems/tasksAndLoopsFJ.svg" type="image/svg+xml" height="360px"> </center> </td> <td> <center> Bulk Synchronous Parallelism<br> <img src="http://synsem.com/images/ems/tasksAndLoopsBSP.svg" type="image/svg+xml" height="360px"> </center> </td> </tr> </table> ## Web Server Process The web server is a conventional single-threaded based on Node.js' built-in HTTP module. As part of the single-threaded initialization EMS is initialized for Fork-Join parallelism and a shared memory is created for the processes to share diagnostic counters and other common state. This shared memory lasts for the life of the web server process and does not persist between invocations of the server. When a request is received, the URL is parsed, then the server enters a parallel region. From the parallel region each process creates or attaches to shared memory created ## Example Start the server: `node webServer.js [# of processes, default=8]` From another terminal or browser, issue requests to the server. A parallel region is created for each request received by the web server, handling the single request with multiple processes. Different variables in the response are used to illustrate different types of data updates. - `requestN` - Every request is given an unique ID - `sessionData` - Each process records it's "work" in the private EMS memory allocated for the session (`foo` or `bar`). The results in the form `(Req:<Request Number>/<EMS ProcessID>)`, the processes may complete in any order, but each request is handled sequentially. - `bignum` - The sum of a loop incrementing a counter in session private EMS memory - `randomSum` - The sum of random numbers generated by all the processes, stored in the shared global EMS memory Following the join at the end of the parallel region, single-threaded execution continues, copying the different variables into a response object ``` dunlin> curl 'http://localhost:8080/foo?new&keep' # Create a new persistent memory for session "foo" {"requestN":0,"sessionData":"0(Req:0/2) (Req:0/7) (Req:0/1) (Req:0/4) (Req:0/5) (Req:0/3) (Req:0/0) (Req:0/6) ","bignum":100000,"randomSum":6103} dunlin> curl 'http://localhost:8080/foo?old&keep' # Modify the existing "foo" memory {"requestN":1,"sessionData":"0(Req:0/2) (Req:0/7) (Req:0/1) (Req:0/4) (Req:0/5) (Req:0/3) (Req:0/0) (Req:0/6) (Req:1/0) (Req:1/4) (Req:1/1) (Req:1/3) (Req:1/5) (Req:1/7) (Req:1/6) (Req:1/2) ","bignum":200000,"randomSum":16670} dunlin> curl 'http://localhost:8080/bar?old' # Error because "bar" does not yet exist, 'keep' implied ERROR: Requested "old" shared memory bar does not already exist. dunlin> curl 'http://localhost:8080/bar?new&free' # Create and free session memory "bar" {"requestN":3,"sessionData":"0(Req:3/4) (Req:3/7) (Req:3/5) (Req:3/3) (Req:3/0) (Req:3/6) (Req:3/2) (Req:3/1) ","bignum":100000,"randomSum":25530} dunlin> curl 'http://localhost:8080/foo?old&keep' # Modify the existing "foo" memory again {"requestN":4,"sessionData":"0(Req:0/2) (Req:0/7) (Req:0/1) (Req:0/4) (Req:0/5) (Req:0/3) (Req:0/0) (Req:0/6) (Req:1/0) (Req:1/4) (Req:1/1) (Req:1/3) (Req:1/5) (Req:1/7) (Req:1/6) (Req:1/2) (Req:4/0) (Req:4/5) (Req:4/2) (Req:4/7) (Req:4/6) (Req:4/1) (Req:4/3) (Req:4/4) ","bignum":300000,"randomSum":30114} dunlin> curl 'http://localhost:8080/foo?new&free' # Modify the existing "foo" memory again, this time freeing it {"requestN":5,"sessionData":"0(Req:5/4) (Req:5/7) (Req:5/5) (Req:5/0) (Req:5/2) (Req:5/6) (Req:5/1) (Req:5/3) ","bignum":100000,"randomSum":36887} dunlin> curl 'http://localhost:8080/foo?old&free' # The memory "foo" has been released ERROR: Requested "old" shared memory foo does not already exist. ``` ###### Copyright (C)2017 Jace A Mogill - All Rights Reserved.