A straightforward definition of multi-threaded functions for NodeJS and browser

栏目: IT技术 · 发布时间: 4年前

内容简介:The tool allows to define functions which are going to be executed in a separate thread in the most straightforward way. It has zero dependencies and it doesn't require anything else like an additional Webpack plugin. elegant-threading works both at NodeJS

elegant-threading

A straightforward definition of multi-threaded functions for NodeJS and browser

The tool allows to define functions which are going to be executed in a separate thread in the most straightforward way. It has zero dependencies and it doesn't require anything else like an additional Webpack plugin. elegant-threading works both at NodeJS and browsers which makes possible to develop universal functions with heavy calculations (finding prime numbers, working with heavy amounts of data, etc) and publish them at NPM to be used at any of these environments.

Install it via npm i elegant-threading or use as a global variable called elegantThreading in a non-CJS environment (see dist/ folder).

Let's say you have a function which runs some heavy calculations:

function heavyCalculations(a, b, c) {
  console.log('calculating a heavy thing');
  return calculateHeavyThing(a, b, c);
}

// the main thread is blocked while the function is executed
const result = heavyCalculations(a, b, c);

If it blocks the main thread you can wrap heavyCalculations by the elegant-threading function and make your code wait a returned promise to be resolved.

const thread = require('elegant-threading');

const heavyCalculations = thread(function heavyCalculations(a, b, c) {
  // yep, console methods also work despite the fact that this is a Worker
  console.log('calculating a heavy thing');
  return calculateHeavyThing(a, b, c);
});

// main thread isn't blocked anymore
const result = await heavyCalculations(a, b, c);

The only requirement to the passed function is that it needs to be implemented as a pure function because it has its own scope where other variables defined at the main thread aren't available including global ones like window . For more info see Web Worker docs . Workers of NodeJS environment in its turn is more flexible at this case but it's still recommended to follow the pureness of your function to make it work at both environments.

Forking via threadedFunction.fork()

When a threaded function is defined it creates a single instance of Worker class (based on environment) which means that if you call the function multiple times it's going to wait for other calls to be done. Let's say the following function execution takes 1 second.

const heavyCalculations = thread(function heavyCalculations(arg) {
  return calculateHeavyThing(arg); // 1 second
});

console.time('exec');
const [result1, result2, result3] = await Promise.all([
  heavyCalculations(a),
  heavyCalculations(b),
  heavyCalculations(c),
]);
console.timeEnd('exec'); // 3 seconds

The execution is going to take ~3 seconds because another function isn't able to be called before previous is done.

To make this code run even faster you can fork the threaded function to create its own worker per every fork. It can be made by using fork method of a returned threaded function.

const heavyCalculations = thread(function heavyCalculations(arg) {
  return calculateHeavyThing(arg); // 1 second
});

const heavyCalculationsFork1 = heavyCalculations.fork();
const heavyCalculationsFork2 = heavyCalculations.fork();
const heavyCalculationsFork3 = heavyCalculations.fork();

console.time('exec');
const [result1, result2, result3] = await Promise.all([
  heavyCalculationsFork1(a),
  heavyCalculationsFork2(b),
  heavyCalculationsFork3(c),
]);
console.timeEnd('exec'); // 1 second

Overall execution time is going to be not more than execution time of the heaviest thread because after they were forked they're going to be executed independently. At the example above it's going to take ~1 second.

Thread termination via threadedFunction.terminate()

If a forked function is done its job and you want to make it process to die you can terminate it easily.

const heavyCalculations = thread(function heavyCalculations(a, b, c) {
  return calculateHeavyThing(a, b, c);
});

const result1 = await heavyCalculations(a, b, c);

heavyCalculations.terminate();

const result2 = await heavyCalculations(a, b, c); // error

Code splitting

If you want to split a big threaded function into smaller functions it's recommended to do it inside the threaded function.

const heavyCalculations = thread(function heavyCalculations(a, b, c) {
  function foo() {
    // do something
  }

  function bar() {
    // do something
  }

  foo();

  bar();

  return someResult;
});

const result = await heavyCalculations(a, b, c);

But there is another way to do that. You can define some functions at the main thread (remember about their pureness!) and pass them as an array as a second argument of elegant-threading function.

function foo() {
  // do something
}

function bar() {
  // do something
}

function main(a, b, c) {
  foo();
  bar();

  return someResult;
}

const heavyCalculations = thread(main, [foo, bar]); // <---

const result = await heavyCalculations(a, b, c);

Is required that every exported function needs to be defined as function declaration . This approach has one downside: since they're stringified to be also a part of an inline worker, an error is thrown inside them may show you a wrong line number. But it can be debugged with the help of console.log method or other console methods.

Tests

Tests can be run via npm test . They're powered by Jasmine and Karma to make them to be executed both at NodeJS and browser environments.

Additional information

  • Transferable objects aren't able to be transferred yet because they become unavailable at other threads (for the main thread and for other forks). If you have an idea how it could be done in a nice and straightforward way, please create an issue.

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

用户思维+:好产品让用户为自己尖叫

用户思维+:好产品让用户为自己尖叫

[美] Kathy Sierra / 石航 / 人民邮电出版社 / 2017-9 / 69.00元

畅销产品与普通产品的本质区别是什么?若没有巨额预算、不爱营销噱头、不开奢华的产品发布会,如何打造可持续成功的产品?本书针对上述问题提出了新颖的观点:用户并不关心产品本身有多棒,而是关心使用产品时自己有多棒。作者利用其多年的交互设计经验,生动阐释了这一观点背后的科学。可贵的是,本书并不止步于解释“为什么”,还清晰呈现了“怎么做”。 本书风格活泼、图文并茂,其对话式内容既引人入胜,又引人深思,适......一起来看看 《用户思维+:好产品让用户为自己尖叫》 这本书的介绍吧!

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具