native-threads
v0.2.0
Published
Node.js native multithreading addon with TypeScript job compilation via scriptc
Maintainers
Readme
native-threads
High-performance Node.js native multithreading addon with on-demand TypeScript JIT compilation via scriptc and true OS threads (std::thread / N-API).
npm install native-threadsOverview
native-threads bypasses the overhead of V8 isolates and message-passing serialization by providing:
- True OS Threads: Spawns background worker threads using native C++ (
std::thread) and libuv. - On-Demand TS JIT Compilation: Compiles
.tsjob files directly to native C shared libraries (.so/.dll/.dylib) viascriptc, loaded dynamically at runtime viadlopen/LoadLibrary. - Zero-Copy Shared Memory: Lock-free & synchronized shared data types (
SharedInt,SharedArrayBuffer,SharedString,SharedMutex). - Rich Synchronization Primitives: Concurrency coordination tools (
RWLock,Semaphore,RecursiveMutex,SpinLock). - Dual Import Formats: Full support for both ESM (
import) and CommonJS (require).
Documentation
Detailed documentation and references are organized in the docs/ directory:
| Document | Topic & Content |
| :--- | :--- |
| Architecture & JIT Lifecycle | Technical breakdown of scriptc transpilation, clang compilation, caching, and runtime execution. |
| Thread & Job Execution API | Complete reference for spawn, join, and threadResult. |
| Dynamic Job Management API | Dynamic loading (loadJobs, unloadJobs), reflection (getJobNames, getJobInfo), and TS rules. |
| Shared Memory Data Structures | SharedInt, SharedArrayBuffer, SharedString, and SharedMutex. |
| Synchronization Primitives | RWLock, Semaphore, RecursiveMutex, SpinLock, and selection guide. |
| Performance Benchmarks | CPU-bound benchmark metrics and speedup comparisons against single-threaded JS. |
Quick Reference / Export Matrix
| Export | Type | Namespace Alias | Description | Reference |
| :--- | :--- | :--- | :--- | :--- |
| spawn | Function | threads.spawn, jobs.spawn | Spawns an OS thread to run a registered TS job with numeric & shared primitive inputs. | Docs |
| join | Function | threads.join | Asynchronously awaits completion of an array of ThreadHandles without blocking the event loop. | Docs |
| threadResult | Function | threads.result | Retrieves the numeric return value of a completed thread, or throws if an error occurred. | Docs |
| loadJobs | Function | jobs.load | Compiles (if changed) and loads a .ts file, .json manifest, or binary library into runtime. | Docs |
| unloadJobs | Function | jobs.unload | Unloads the active job shared library from memory. | Docs |
| getJobNames | Function | jobs.names | Returns an array of all registered job function names. | Docs |
| getJobInfo | Function | jobs.info | Returns a dictionary mapping registered job names to their metadata (e.g., arity). | Docs |
| buildJobSharedLibrary | Function | jobs.build | Compiles a TypeScript source file into a cached shared library binary without loading it. | Docs |
| SharedInt | Class | shared.Int, shared.SharedInt | Thread-safe 64-bit atomic integer supporting lock-free atomic get, set, and add. | Docs |
| SharedArrayBuffer | Class | shared.Buffer, shared.SharedArrayBuffer | Thread-safe contiguous byte buffer with internal reader-writer locking. | Docs |
| SharedString | Class | shared.String, shared.SharedString | Thread-safe UTF-8 string container protected by internal shared mutex. | Docs |
| SharedMutex | Class | sync.Mutex, shared.Mutex | Mutual exclusion lock for coordinating thread access (lock, tryLock, unlock). | Docs |
| RWLock | Class | sync.RWLock | Reader-Writer lock supporting multiple concurrent readers or a single exclusive writer. | Docs |
| Semaphore | Class | sync.Semaphore | Counting semaphore for resource-pool bounding and token acquisition. | Docs |
| RecursiveMutex | Class | sync.RecursiveMutex | Re-entrant mutex allowing the same thread to acquire nested locks without deadlocking. | Docs |
| SpinLock | Class | sync.SpinLock | Low-latency atomic busy-wait lock for ultra-short (<1μs) critical sections. | Docs |
| jobs | Namespace | — | Grouped namespace for job management (load, unload, spawn, names, info, build). | Docs |
| sync | Namespace | — | Grouped namespace for synchronization primitives (Mutex, RWLock, Semaphore, etc.). | Docs |
| shared | Namespace | — | Grouped namespace for shared data structures (Int, Buffer, String, Mutex). | Docs |
| threads | Namespace | — | Grouped namespace for thread execution (spawn, join, result). | Docs |
Quick Start
1. Define Worker Jobs (jobs.ts)
Export pure TypeScript functions accepting and returning number (compiled to native f64):
// jobs.ts
export function fib(n: number): number {
return n < 2 ? n : fib(n - 1) + fib(n - 2);
}
export function countPrimes(start: number, end: number): number {
let count = 0;
for (let i = start; i <= end; i++) {
if (i < 2) continue;
let isP = true;
for (let d = 2; d * d <= i; d++) {
if (i % d === 0) { isP = false; break; }
}
if (isP) count++;
}
return count;
}2. Load & Execute in Node.js (ESM / CJS)
import { jobs, spawn, join, threadResult, SharedInt } from "native-threads";
import path from "node:path";
// 1. Auto-compiles & caches on first run; reloads automatically on code changes
jobs.load(path.join(process.cwd(), "jobs.ts"));
async function main() {
// 2. Spawn native OS threads running compiled C code
const h1 = spawn("countPrimes", 1, 500000);
const h2 = spawn("countPrimes", 500001, 1000000);
// 3. Or pass shared atomic primitives and arrays
const counter = new SharedInt(20);
const h3 = spawn("fib", counter);
// 4. Asynchronously await completion without blocking the event loop
await join([h1, h2, h3]);
// 5. Retrieve numeric return results
console.log("Total primes [1..1M]:", threadResult(h1) + threadResult(h2));
console.log("fib(20):", threadResult(h3));
}
main();Grouped Namespaces
For organized, domain-specific imports, native-threads provides four top-level namespaces:
import { jobs, sync, shared, threads } from "native-threads";
// jobs: load, unload, spawn, names, info, build
jobs.load("./jobs.ts");
const jobList = jobs.names();
// sync: Mutex, SharedMutex, RWLock, Semaphore, RecursiveMutex, SpinLock
const rw = new sync.RWLock();
const sem = new sync.Semaphore(4);
// shared: Int, SharedInt, Buffer, SharedArrayBuffer, String, SharedString, Mutex, SharedMutex
const counter = new shared.Int(0);
const buf = new shared.Buffer(1024);
// threads: spawn, join, result, threadResult
const h = threads.spawn("fib", 30);
await threads.join([h]);
const res = threads.result(h);Examples & Benchmarks
Standalone consumer examples are available in example/:
example/simple/: Minimal starter with TypeScript workers, atomic integers, and mutual exclusion.example/complex/: Multi-worker compute pool (primes, Mandelbrot, Monte Carlo Pi, N-Body physics, matrix multiplication), shared buffers, and synchronization locks.
Run benchmarks:
npm testSetup & Build
Requirements
- Node.js >= 24
- CMake >= 3.15
- C++17 compliant compiler (Clang, GCC, or MSVC)
# Clone and install dependencies
git clone https://github.com/div02-afk/threaded.git
cd threaded
npm install
# Build native addon
npm run build
# Run test suite
npm test
# Run examples
npm run example:simple
npm run example:complex