Socket
Socket
Sign inDemoInstall

threadedclass

Package Overview
Dependencies
4
Maintainers
2
Versions
69
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

    threadedclass

[![Lint and Test](https://github.com/nytamin/threadedClass/actions/workflows/lint-and-test.yml/badge.svg)](https://github.com/nytamin/threadedClass/actions/workflows/lint-and-test.yml) [![codecov](https://codecov.io/gh/nytamin/threadedClass/branch/master/


Version published
Maintainers
2
Created

Changelog

Source

1.1.2 (2022-11-02)

Bug Fixes

  • bug fix: it wasn't possible to call ThreadedClassManager.restart multiple times for the same instance (e93e5c5)

Readme

Source

Threaded class

Lint and Test codecov

Fork instances of classes (while keeping typings) with one line of code.

Getting started

npm install threadedclass

Let's say you have a class that has several computational-heavy methods:

// Normal, single-threaded way:
import { Professor } from './professor'

function getStory() {
  let mrSmith = new Professor('maths', 'greek')
  let story = mrSmith.talkAboutAncientGreece() // takes a loong time
  return story
}

Threaded-class helps you create an asynchronous version of the instance of that class. The instance will have almost the same typings-API as the original (all methods return promises instead), but will run in a separate thread.

// Multi-threaded, asynchronous way:
import { threadedClass} from 'threadedclass'
import { Professor } from './professor'

async function getStory() {
  let mrSmith = await threadedClass<Professor>('./professor.js', 'Professor', ['maths', 'greek'])
  let story = await mrSmith.talkAboutAncientGreece() // still takes a loong time, but now runs in a separate thread
  return story
}

The instance returned by threadedClass() has methods equivalent to the original, but all properties and methods will be asynchronous (return Promises).

API

API reference

NodeJS: Typescript example

import { threadedClass} from  'threadedclass'
import { Professor } from './professor'

threadedClass<Professor>(
   './professor.js',     // Path to imported module (this should be the same path as is in require('XX') or import {class} from 'XX'} )
   'Professor' ,        // The export name for the class to be forked
   ['maths', 'greek'], // Array of arguments to be fed into the class constructor
   {} // Config (see below)
)
.then((instance) => {
   return mrSmith.talkAboutAncientGreece() // All methods returns a Promise
})
.then((story) => {
   console.log(story)
})

NodeJS: Javascript example

var threadedClass = require('threadedclass').threadedClass
var Professor = require('./professor')

threadedClass('./professor.js', Professor, ['maths', 'greek'])
.then((instance) => {
   return mrSmith.talkAboutAncientGreece() // All methods returns a Promise
})
.then((story) => {
   console.log(story)
})

Browser: Javascript example

Example

<script type="text/javascript" src="lib/threadedClass.js"></script>
<script type="text/javascript" src="professor.js"></script>
<script type="text/javascript">
   var threadedClass = ThreadedClass.threadedClass

   threadedClass('../professor.js', Professor, ['maths', 'greek'], { // path to module is relative to threadedClass.js
      pathToWorker: 'lib/threadedclass-worker.js' // in browser, a path to the worker-scrip must also be provided
   })
   .then((instance) => {
   return mrSmith.talkAboutAncientGreece() // All methods returns a Promise
   })
   .then((story) => {
      console.log(story)
   })
</script>

Options

An optional options object can be passed to threadedClass() with the following properties:

OptionTypeDescription
threadUsagenumberA number between 0 - 1, how large part of a thread the instance takes up. For example; if set to 0.1, a thread will be re-used for up to 10 instances.
threadIdstringSet to an arbitrary id to put the instance in a specific thread. Instances with the same threadIds will be put in the same thread.
autoRestartbooleanIf the process crashes or freezes it's automatically restarted. (ThreadedClassManager will emit the "restarted" event upon restart)
disableMultithreadingbooleanSet to true to disable multi-threading, this might be useful when you want to disable multi-threading but keep the interface unchanged.
pathToWorkerstringSet path to worker, used in browser
freezeLimitnumber(milliseconds), how long to wait before considering the child to be unresponsive. (default is 1000 ms)

Features

Supported imports

  • Classes imported from your own modules. import { MyClass } from './myModule'
  • Classes imported from external dependencies. import { DatClass } from 'dat-library'
  • Classes importted from native Node modules. import { StringDecoder } from 'string_decoder'

Supported methods, arguments / parameters & return values

When calling a method of your threaded instance (threaded.myMethod()), there are some limitations to what data-types are allowed to be provided and returned.

Supported data types
  • All JSON-serializable types; numbers, strings, arrays, objects etc..
  • Buffers
  • Functions (such as callbacks or returned functions)
Unsupported data types
  • Non-JSON-encodable types, such as objects with cyclic references (except when in worker_threads, then it's fine).
  • Instances of classes (the instance will be serialized as JSON and piped through, but its methods will not).

Using with electron

Electron does not properly support asar files with worker_threads. When loading a file to execute, it must reside on disk and not inside of the asar file containing all of your application code.

ThreadedClass can workaround this, by using a small preloader that is loaded from disk by the parent, and evaled by the worker_thread. The default electron loader utilises the asar-node package to provide support for reading from the asar to the new thread. This preloader is only used for electron when it is detected that the code to load is inside an asar file, and if a custom loader is not specified.

The loader can be overridden by defining the THREADEDCLASS_WORKERTHREAD_LOADER environment variable containing an absolute path to the desired loader. This can be done inside node before the thread is created. This file can reside inside an asar, or anywhere else the parent can load via fs.readFileSync. It is recommended to bundle this file with browserify or webpack. See asar-loader.ts as an example

Known limitations

  • The to-be-threaded class must not be referencing any global variables, as the class is run in its own sandbox.
  • No garbage-collection of callback-functions Currently, if you give a callback to a method (like so: threaded.myMethod(() => {})) a reference to the method will be stored indefinitely, because we cannot determine if the reference is valid in the child process.
  • There is a noticable delay when spawning a new thread, and since each thread is its own Node-process it uses up a few Megabytes of memory. If you intend to spawn many instances of a class, consider using the threadUsage option (for example threadUsage: 0.1 will put 10 instances in a thread before spawning a new).

Under the hood

Used API:s

Different API:s will be used for threading, depending on the platform:

PlatformAPI used
BrowserWeb-workers
NodeJS <10.xChild process
NodeJS 10.x - 11.7Worker-threads (if node --experimental-worker flag is enabled)
NodeJS >11.8Worker-threads

Notes on performance

Doing method-calls to threads is slower than when running in a single thread. The greatest benefit comes when there is heavy computations to be made.

This table shows measured round-trip times of just calling a method:

PlatformAPI usedAvg. time per call
NodeJS 8.17Single-thread mode0.000200 ms per call
NodeJS 8.17Child process0.090000 ms per call
NodeJS 10.15Single-thread mode0.000078 ms per call
NodeJS 10.15Child process0.076000 ms per call
NodeJS 10.15Worker-threads0.045000 ms per call
NodeJS 12.22Single-thread mode0.000064 ms per call
NodeJS 12.22Worker-threads0.053000 ms per call
NodeJS 14.18Single-thread mode0.000069 ms per call
NodeJS 14.18Worker-threads0.055000 ms per call
NodeJS 16.14Single-thread mode0.000072 ms per call
NodeJS 16.14Worker-threads0.052000 ms per call
Browser (Chrome 99)Single-thread mode0.002500 ms per call
Browser (Chrome 99)Web-workers0.094202 ms per call

Keywords

FAQs

Last updated on 02 Nov 2022

Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc