Open-source project
mogill/ems avatar
mogill/ems

EMS: shared memory that outlives the process using it

Extended Memory Semantics - Persistent shared object memory and parallelism for Node.js and Python

604 stars36 forksJavaScriptNOASSERTION

At a glance

What is it?
Extended Memory Semantics gives Node.js, Python and C programs one shared object space backed by persistent memory, with atomic operations, transactions and OpenMP-style collectives, aimed at jobs that fit on one server but not on one core.
Who is it for?
Adopt EMS if you have a workload that fits in one server's memory but not on one core, and you want Node, Python and C processes to work on the same data without a network boundary. Do not adopt it for a new project today, since the last tagged release is from 2017 and the native addon targets an old Node ABI, and check the BSD-3-Clause package licence against the repository's own licence file first.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 9 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Memory that is not owned by any process

Extended Memory Semantics is a library and a runtime model that makes persistent shared memory parallelism possible between Node.js, Python and C/C++. The unifying idea is that EMS handles both the synchronization and the storage primitives for parallel programming, so that any number or kind of processes can share objects, the library manages synchronization and object coherency, and the data is persisted to non-volatile memory and to secondary storage. The animated example in the documentation makes the lifecycle concrete. You start a Node.js REPL and create an EMS memory, store a value, open a second session, start the Python REPL, connect Python to the same shared memory, and see the object created from JavaScript. You modify it in Python and see the change in JavaScript. Then you exit both REPLs so no program is running to own the memory, restart Python, and the memory is still there. That last step is the distinguishing feature, since shared memory that disappears when the last process exits is an ordinary IPC segment, not persistent memory.

The same objects, in three languages

The inter-language example, with matching JavaScript and Python files, is the proof that this is more than a Node addon. The demonstration continues with a counter initialised from Python, an atomic fetch-and-add performed from JavaScript, a loop in Python incrementing the counter while JavaScript reads and modifies it at the same time, and then a deliberate blocking read. Python tries to read empty data and blocks, and the write that marks the memory full resumes Python. That blocking behaviour is deliberate rather than incidental, and it is the design idea the documentation states most clearly, that synchronization is a property of the data rather than a duty for tasks. A task does not have to acquire a lock and remember to release it. A reader simply asks for data that is full and waits, and a writer asks for data that is empty and waits. The repository ships the language bindings side by side, with a nodejs directory, a Python directory, a C++ source tree under src, and a binding.gyp file for the native addon, and the public API documentation and the project website are both published under the mogill.github.io domain.

Atomics, queues and transactions over JSON data

The operations work on any JSON data type, and read-modify-write operations may combine several of them, in the same way you would work with ordinary data. The catalogue of what is available falls into four groups. The atomic operations are read, write, a readers-writer lock, read when full and atomically mark empty, and write when empty and atomically mark full. The primitives are stacks, queues and transactions. The read-modify-write operations are fetch-and-add and compare-and-swap. And the collective operations cover all the basic OpenMP collective operations, with dynamic, block and guided scheduling as well as the full complement of static loop scheduling, plus barriers, master and single execution regions. Two limitations are stated rather than hidden. Atomic read-modify-write operations are available in all concurrency modes, but collectives are not available in user-defined modes. So if you mix languages and ad-hoc processes, you keep the atomics and lose the barriers, which changes how you structure the parallel section.

Three execution models, and the gap they fill

EMS implements three parallel execution models. Fork-join multiprocess starts with a single process that creates new processes as needed, and those processes then wait for each other to complete. Bulk synchronous parallel starts every process at the main entry point executing all the statements, which is the model behind word counting, where the implementation iterates over documents in parallel while maintaining a single shared dictionary across processes and atomically incrementing the count of each word, then sorts the counts and prints the most frequent words with their counts. The third is user-defined, where parallelism may include ad-hoc processes and mixed-language applications. The positioning statement explains where this belongs, and it is a narrower claim than parallelism in general. EMS is targeted at tasks too large for one core or one process but too small for a scalable cluster, since a modern multi-core server has 16 to 32 cores and nearly a terabyte of memory, which means jobs that formerly needed a MapReduce cluster can now run entirely in shared memory on one server without distributed programming.

Benchmarks on one EC2 instance, with the caveats stated

The documentation includes benchmarks and, unusually, the caveats that limit them. The word counting program was measured on an Amazon EC2 instance described as a c4.8xlarge with 132 ECUs, 36 vCPUs at 2.9 GHz, an Intel Xeon E5-2666v3 and 60 GiB of memory, and the scaling levelled off around 16 cores. The project attributes that to the hardware rather than to the library, noting that half of the 36 vCPUs are presumably HyperThreads or otherwise shared resources, and that AWS instances are bandwidth limited to EBS storage, where the Gutenberg corpus is stored. A second benchmark, similar to STREAMS, measures the maximum speed at which EMS can perform double precision floating point operations on the same instance type. A third covers transactions and work queues. The examples directory is the supporting evidence, holding a parallel web server, the word counter, a concurrent queue and transactional memory example, a work queue example, a key value store, the STREAMS benchmark and the inter-language pair.

A native addon, an old Node ABI and a licence question

The implementation is a native addon. The package metadata names the package ems at version 1.6.1, with the entry point at nodejs/ems.js, and the only two runtime dependencies are the bindings loader and node-addon-api, which is the modern Node addon interface. The engines field asks for Node 4.0 or newer, and the header of the Makefile carries the version 1.6.1 and a copyright range of 2016 to 2020, so the code is written against a much older Node than a current release would use. The test script iterates over the JavaScript files in the Tests directory and runs each with an argument of 8, which is the thread count, and the example script runs the concurrent queue and transactional memory example with 8 as well. The licence needs a careful read. The package metadata declares BSD-3-Clause and the Makefile header carries a BSD style redistribution notice, while the repository itself is listed as having a custom licence that GitHub cannot classify, so the LICENSE file is the one to check. The release history stops in 2017, with v1.4.4 in March and v1.4.5 and v1.4.8 in September, while the last push was on 2026-10-14, so the code moves but the tags do not.

Editorial conclusion

Adopt EMS if you have a workload that fits in one server's memory but not on one core, and you want Node, Python and C processes to work on the same data without a network boundary. Do not adopt it for a new project today, since the last tagged release is from 2017 and the native addon targets an old Node ABI, and check the BSD-3-Clause package licence against the repository's own licence file first.

Frequently asked questions

What is Extended Memory Semantics and who is it for?

EMS is a library and runtime model that gives Node.js, Python and C/C++ programs a shared object space with persistence, atomics, transactions and OpenMP-style collectives. It targets work that is too large for one core but too small for a cluster, so it runs in shared memory on a single server.

How does EMS share data between Python and JavaScript?

Both languages connect to the same EMS memory. The documented example stores a value from the Node.js REPL, connects the Python REPL to that memory, modifies the object there and sees the change in JavaScript, and shows that the memory survives after both REPLs exit.

Which parallel execution models does EMS implement?

Three: fork-join multiprocess, bulk synchronous parallel where every process starts at the main entry point, and a user-defined mode that allows ad-hoc and mixed-language processes. Atomic operations work in every mode, but collective operations are not available in the user-defined mode.

What licence is EMS released under?

The package metadata declares BSD-3-Clause and the Makefile header carries a BSD style redistribution notice, while the repository is recorded as having a custom licence that GitHub cannot classify, so read the LICENSE file before you rely on the terms.

Is EMS still maintained?

The repository is not archived and the last push was on 2026-10-14, but the most recent tagged releases are v1.4.4, v1.4.5 and v1.4.8 from 2017, and the package targets Node 4.0 or newer through a native addon.

Official sources

  1. Issues
  2. mogill/ems on GitHub
  3. README
  4. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mogill-ems.svg)](https://hysenlabs.com/projects/mogill-ems)

Was this useful?