0.0.6 • Published 4 months ago

fast-thread v0.0.6

Weekly downloads
-
License
MIT
Repository
github
Last release
4 months ago

šŸš€ fast-thread

fast-thread is a high-performance module designed for ultra-fast object transmission between threads in Node.js, optimizing parallel processing with SharedArrayBuffer, Atomics, and fast-json-stringify.

šŸ”„ Why fast-thread?

In Node.js, thread communication has inherent limitations:

  • No native memory sharing like in other languages.
  • All data must be serialized and sent via messaging, adding overhead.
  • Complex objects cannot be shared natively, requiring costly serialization.

For high-performance applications, reducing serialization time directly improves parallel processing speed.

šŸš€ The Challenge: Finding the Fastest Serialization Method

We tested multiple serialization methods to find the fastest approach for inter-thread communication in Node.js.

Serialization MethodProsCons
JSON (JSON.stringify)Built-in, no dependenciesSlower serialization, larger payload
msgpack-liteCompact binary formatSlower than JSON in V8
CBORCompact and structured binary formatStill slower than JSON
BSONOptimized for MongoDB, fast parsingHigh overhead for small objects
Protobuf.jsCompact, schema-based, high performanceRequires pre-defined schema
fast-json-stringifyFaster than JSON.stringify with schemaStill requires copying in postMessage()
fast-thread šŸš€SharedArrayBuffer + Atomics (No Copy)Requires structured memory handling

After extensive benchmarking, the fastest approach was a combination of:

  • āœ… SharedArrayBuffer for direct memory access
  • āœ… Atomics.wait()/Atomics.notify() for ultra-fast synchronization
  • āœ… fast-json-stringify for zero-copy, schema-based serialization

šŸ“Š Benchmark Results

Our tests measured message throughput (msg/sec) and bandwidth (MB/sec) over a 10s test period.

NameMessagesMessages Per SecondMB Per Second
fast-thread617,48361,748.3065.34
JSON524,23552,423.5055.48
fast-json-stringify500,02450,002.4052.10
BSON420,94642,094.6044.19
Protobuf.js296,34029,634.0029.75
msgpack-lite288,18028,818.0029.86
CBOR223,94522,394.5023.20

šŸš€ fast-thread achieved the best performance with a throughput of ~61,748 messages per second and 65.34 MB/sec.


⚔ Solution: SharedArrayBuffer + Atomics + fast-json-stringify

How It Works

  • SharedArrayBuffer is used for zero-copy memory sharing.
  • Atomics.wait()/Atomics.notify() provide fast synchronization between threads.
  • fast-json-stringify eliminates JSON parsing overhead.

šŸ“Œ Installation

pnpm install fast-thread

šŸ›  Example Usage

Worker Thread (worker_fast.js)

const { workerData } = require("worker_threads");
const fastJson = require("fast-json-stringify");
const { unpackObject, packObject } = require("fast-thread");

const sharedBuffer = workerData;
const stringify = fastJson({
    title: "Example",
    type: "object",
    properties: {
        id: { type: "integer" },
        name: { type: "string" },
        timestamp: { type: "integer" },
        data: { type: "string" }
    }
});

async function processData() {
    while (true) {
        Atomics.wait(sharedBuffer.signal, 0, 0);

        let obj = unpackObject(sharedBuffer);
        if (!obj) continue;

        obj.processed = true;
        packObject(stringify(obj), sharedBuffer, 1);
    }
}

processData();

Main Thread (test.js)

const { FastThread } = require("fast-thread");

(async () => {
    const fastThread = new FastThread("./worker_fast.js", 1024 * 1024)

    fastThread.on("message", (data) => {
        console.log("[Main] Processed data received:", data);
    });

    fastThread.on("terminated", () => {
        console.log("Thread closed");
    });

    for(let i = 0; i < 100; i++){
        fastThread.send({
            id: i,
            name: "User " + i,
            timestamp: Date.now(),
            data: "x".repeat(512)
        });

        await fastThread.awaitThreadReponse();
    }

    setTimeout(() => fastThread.terminate(), 2000);
})();

Since SharedArrayBuffer has a fixed size, it's essential to send messages sequentially, waiting for a response before sending the next job. This prevents buffer overwriting, ensuring each message is processed correctly.

Currently, no parallel message handling system has been implemented, meaning multiple messages cannot be processed simultaneously within the same thread instance.

To handle this limitation, the await fastThread.awaitThreadResponse(); call ensures that each message is processed before sending the next one. Without this mechanism, sending multiple messages at once could result in data loss or overwritten responses.

Main Thread (test-alternative.js)

const { Worker } = require("worker_threads");
const fastJson = require("fast-json-stringify");

const { 
    createSharedBuffer, packObject, 
    unpackObject 
} = require("fast-thread");

const sharedBuffer = createSharedBuffer();
const worker = new Worker("./worker_fast.js", { workerData: sharedBuffer });

const stringify = fastJson({
    title: "Example",
    type: "object",
    properties: {
        id: { type: "integer" },
        name: { type: "string" },
        timestamp: { type: "integer" },
        data: { type: "string" }
    }
});

packObject(stringify({ 
    id: 1, 
    name: "User A", 
    timestamp: Date.now(), 
    data: "x".repeat(512) 
}), sharedBuffer);

const checkResponses = () => {
    Atomics.wait(sharedBuffer.signal, 1, 0);
    const processedData = unpackObject(sharedBuffer, 1);
    console.log("[Main] Processed data received:", processedData);
    setImmediate(checkResponses);
};

šŸ“Œ Conclusion

fast-thread enables blazing-fast thread communication in Node.js using SharedArrayBuffer, Atomics, and fast-json-stringify. This approach eliminates message serialization overhead, delivering unparalleled performance in high-throughput parallel workloads.

0.0.5

4 months ago

0.0.6

4 months ago

0.0.4

4 months ago

0.0.3

4 months ago