threads vs node-worker-threads-pool
Node.js Concurrency Libraries Comparison
1 Year
threadsnode-worker-threads-poolSimilar Packages:
What's Node.js Concurrency Libraries?

Concurrency libraries in Node.js allow developers to execute multiple tasks simultaneously, improving performance and responsiveness in applications. These libraries utilize worker threads to handle CPU-intensive operations without blocking the main event loop, which is crucial for maintaining the non-blocking nature of Node.js. By leveraging these libraries, developers can efficiently manage parallel processing, making it easier to build scalable applications that can handle high workloads and complex computations without degrading performance.

Package Weekly Downloads Trend
Github Stars Ranking
Stat Detail
Package
Downloads
Stars
Size
Issues
Publish
License
threads152,8103,418-1263 years agoMIT
node-worker-threads-pool25,294293-163 years agoMIT
Feature Comparison: threads vs node-worker-threads-pool

Thread Management

  • threads:

    threads offers more granular control over individual worker threads, allowing developers to create, terminate, and communicate with threads directly. This flexibility is beneficial for applications that require specific thread management strategies or need to handle complex inter-thread communication.

  • node-worker-threads-pool:

    node-worker-threads-pool provides a straightforward API for creating and managing a pool of worker threads. It allows you to specify the number of threads in the pool, automatically handles the lifecycle of threads, and reuses them for multiple tasks, which minimizes the overhead of thread creation and destruction.

Ease of Use

  • threads:

    threads, while powerful, has a steeper learning curve due to its extensive feature set. Developers may need to invest more time to understand its capabilities and best practices for using message passing and shared memory effectively.

  • node-worker-threads-pool:

    node-worker-threads-pool is designed for simplicity and ease of use. Its API is intuitive, making it easy for developers to implement thread pooling without extensive boilerplate code. This is ideal for developers who want to quickly add concurrency to their applications without a steep learning curve.

Performance

  • threads:

    threads can achieve high performance by allowing for more complex communication patterns and shared memory access, which can be beneficial for CPU-bound tasks. However, this complexity may introduce additional overhead if not managed properly.

  • node-worker-threads-pool:

    By reusing threads, node-worker-threads-pool can significantly improve performance in scenarios with frequent task execution, as it reduces the overhead associated with creating and destroying threads. This makes it suitable for applications with high concurrency demands.

Communication Mechanisms

  • threads:

    threads supports both message passing and shared memory, providing more flexibility in how data is shared between threads. This can lead to performance improvements in certain scenarios, especially when large amounts of data need to be shared without the overhead of serialization.

  • node-worker-threads-pool:

    node-worker-threads-pool primarily uses message passing for communication between the main thread and worker threads. This approach is straightforward and fits well with the event-driven nature of Node.js, making it easy to implement asynchronous task handling.

Use Cases

  • threads:

    threads is better suited for applications that involve heavy computations or require complex data sharing between threads, such as scientific simulations, real-time data processing, or applications that need to maintain state across multiple threads.

  • node-worker-threads-pool:

    node-worker-threads-pool is ideal for applications that require efficient handling of multiple short-lived tasks, such as image processing, data transformation, or any scenario where tasks can be parallelized without complex inter-thread communication.

How to Choose: threads vs node-worker-threads-pool
  • threads:

    Choose threads if you require a more feature-rich library that provides advanced capabilities such as message passing, shared memory, and more extensive control over worker threads. It is suitable for applications that need fine-grained control over thread management and communication.

  • node-worker-threads-pool:

    Choose node-worker-threads-pool if you need a simple and lightweight solution for managing a pool of worker threads. It is particularly useful for scenarios where you want to limit the number of concurrent threads and reuse them for multiple tasks, optimizing resource usage and reducing overhead.

README for threads

threads.js

Build status npm (tag) Chat room


Offload CPU-intensive tasks to worker threads in node.js, web browsers and electron using one uniform API.

Uses web workers in the browser, worker_threads in node 12+ and tiny-worker in node 8 to 11.

Features

  • First-class support for async functions & observables
  • Write code once, run it on all platforms
  • Manage bulk task executions with thread pools
  • Use require() and import/export in workers
  • Works great with webpack

Version 0.x

You can find the old version 0.12 of threads.js on the v0 branch. All the content on this page refers to version 1.0 which is a rewrite of the library with a whole new API.

Installation

npm install threads tiny-worker

You only need to install the tiny-worker package to support node.js < 12. It's an optional dependency and used as a fallback if worker_threads are not available.

Platform support

Run on node.js

Running code using threads.js in node works out of the box.

Note that we wrap the native Worker, so new Worker("./foo/bar") will resolve the path relative to the module that calls it, not relative to the current working directory.

That aligns it with the behavior when bundling the code with webpack or parcel.

Webpack build setup

Webpack config

Use with the threads-plugin. It will transparently detect all new Worker("./unbundled-path") expressions, bundles the worker code and replaces the new Worker(...) path with the worker bundle path, so you don't need to explicitly use the worker-loader or define extra entry points.

  npm install -D threads-plugin

Then add it to your webpack.config.js:

+ const ThreadsPlugin = require('threads-plugin');

  module.exports = {
    // ...
    plugins: [
+     new ThreadsPlugin()
    ]
    // ...
  }

Node.js bundles

If you are using webpack to create a bundle that will be run in node (webpack config target: "node"), you also need to specify that the tiny-worker package used for node < 12 should not be bundled:

  module.exports = {
    // ...
+   externals: {
+     "tiny-worker": "tiny-worker"
+   }
    // ...
}

Make sure that tiny-worker is listed in your package.json dependencies in that case.

When using TypeScript

Note: You'll need to be using Typescript version 4+, as the types generated by threads.js are not supported in Typescript 3.

Make sure the TypeScript compiler keeps the import / export statements intact, so webpack resolves them. Otherwise the threads-plugin won't be able to do its job.

  module.exports = {
    // ...
    module: {
      rules: [
        {
          test: /\.ts$/,
          loader: "ts-loader",
+         options: {
+           compilerOptions: {
+             module: "esnext"
+           }
+         }
        }
      ]
    },
    // ...
  }
Parcel bundler setup

You need to import threads/register once at the beginning of your application code (in the master code, not in the workers):

  import { spawn } from "threads"
+ import "threads/register"

  // ...

  const work = await spawn(new Worker("./worker"))

This registers the library's Worker implementation for your platform as the global Worker. This is necessary, since you cannot import { Worker } from "threads" or Parcel won't recognize new Worker() as a web worker anymore.

Be aware that this might affect any code that tries to instantiate a normal web worker Worker and now instead instantiates a threads.js Worker. The threads.js Worker is just a web worker with some sugar on top, but that sugar might have unexpected side effects on third-party libraries.

Everything else should work out of the box.

Getting Started

Basics

// master.js
import { spawn, Thread, Worker } from "threads"

const auth = await spawn(new Worker("./workers/auth"))
const hashed = await auth.hashPassword("Super secret password", "1234")

console.log("Hashed password:", hashed)

await Thread.terminate(auth)
// workers/auth.js
import sha256 from "js-sha256"
import { expose } from "threads/worker"

expose({
  hashPassword(password, salt) {
    return sha256(password + salt)
  }
})

spawn()

The hashPassword() function of the auth object in the master code proxies the call to the hashPassword() function in the worker:

If the worker's function returns a promise or an observable then you can just use the return value as such in the master code. If the function returns a primitive value, expect the master function to return a promise resolving to that value.

expose()

Use expose() to make a function or an object containing methods callable from the master thread.

In case of exposing an object, spawn() will asynchronously return an object exposing all the object's functions. If you expose() a function, spawn will also return a callable function, not an object.

Usage

Find the full documentation on the website:

Webpack

Threads.js works with webpack. Usually all you need to do is adding the threads-plugin.

See Build with webpack on the website for details.

Debug

We are using the debug package to provide opt-in debug logging. All the package's debug messages have a scope starting with threads:, with different sub-scopes:

  • threads:master:messages
  • threads:master:spawn
  • threads:master:thread-utils
  • threads:pool:${poolName || poolID}

Set it to DEBUG=threads:* to enable all the library's debug logging. To run its tests with full debug logging, for instance:

DEBUG=threads:* npm test

License

MIT