node-worker-threads-pool
Advanced tools
Comparing version 1.0.0 to 1.0.1
134
index.js
@@ -1,132 +0,4 @@ | ||
const { Worker } = require('worker_threads'); | ||
/** | ||
* worker in the pool. | ||
*/ | ||
class PoolWorker extends Worker { | ||
/** | ||
* @param { Pool } pool pool that own this worker | ||
*/ | ||
constructor(pool) { | ||
super(pool.filePath); | ||
this.pool = pool; | ||
// working status. | ||
this.isFree = true; | ||
// call done method when work finished. | ||
this.prependListener('message', () => this.done()); | ||
this.once('exit', code => { | ||
if (this.pool.isDeprecated || code === 0) { | ||
// exit normally, do nothing. | ||
return; | ||
} | ||
// exit with exception. | ||
this.handleException(); | ||
}); | ||
} | ||
/** | ||
* start working. | ||
* @param {*} param | ||
*/ | ||
work(param) { | ||
this.isFree = false; | ||
this.postMessage(param); | ||
} | ||
/** | ||
* work finished. | ||
*/ | ||
done() { | ||
this.isFree = true; | ||
} | ||
/** | ||
* request pool to replace this | ||
* broken worker with a new one. | ||
*/ | ||
handleException() { | ||
this.pool._replace(this); | ||
} | ||
} | ||
/** | ||
* "waiting" for the next event loop. | ||
*/ | ||
function nextLoop() { | ||
return new Promise((resolve, _) => { | ||
setTimeout(resolve, 20); | ||
}); | ||
} | ||
/** | ||
* threads pool with node's worker_threads. | ||
*/ | ||
module.exports = class Pool { | ||
/** | ||
* @param { String } filePath absolute path of the worker script. | ||
* @param { Number } num number of workers. | ||
*/ | ||
constructor(filePath, num) { | ||
if (typeof filePath !== 'string') { | ||
throw new Error('"filename" must be the type of string!'); | ||
} | ||
if (typeof num !== 'number') { | ||
throw new Error('"max" must be the type of number!'); | ||
} | ||
if (Number.isNaN(num)) { | ||
throw new Error('"max" must not be NaN!'); | ||
} | ||
if (num < 1) { | ||
throw new Error('"max" must not be lower than 1!'); | ||
} | ||
// path of the script this pool will use. | ||
this.filePath = filePath; | ||
// pool status. | ||
this.isDeprecated = false; | ||
// worker list. | ||
this.workers = Array.from(new Array(num), _ => new PoolWorker(this)); | ||
} | ||
/** | ||
* choose a worker to do this task. | ||
* @param {*} param | ||
*/ | ||
async exec(param) { | ||
const worker = this.workers.find(worker => worker.isFree); | ||
if (!worker) { | ||
// pool is busy, "waiting" for the next event loop. | ||
await nextLoop(); | ||
return this.exec(param); | ||
} | ||
return new Promise((resolve, reject) => { | ||
worker.once('message', resolve); | ||
worker.once('error', reject); | ||
worker.work(param); | ||
}); | ||
} | ||
/** | ||
* replace this broken worker with a new one. | ||
* @param { PoolWorker } worker | ||
*/ | ||
_replace(worker) { | ||
const index = this.workers.indexOf(worker); | ||
if (index !== -1) { | ||
this.workers[index] = new PoolWorker(this); | ||
// console.log('--------------------- Replaced --------------------'); | ||
} | ||
} | ||
/** | ||
* terminate all workers in this pool. | ||
*/ | ||
destroy() { | ||
this.isDeprecated = true; | ||
this.workers.forEach(worker => worker.terminate()); | ||
this.workers = null; | ||
} | ||
module.exports = { | ||
StaticPool: require('./src/static-pool'), | ||
DynamicPool: require('./src/dynamic-pool') | ||
} |
{ | ||
"name": "node-worker-threads-pool", | ||
"version": "1.0.0", | ||
"version": "1.0.1", | ||
"description": "simple worker pool using node's worker_threads api.", | ||
@@ -10,3 +10,5 @@ "main": "index.js", | ||
"scripts": { | ||
"example": "node --experimental-worker ./example" | ||
"static-function": "node --experimental-worker ./example/static-with-function", | ||
"static-file": "node --experimental-worker ./example/static-with-worker-file", | ||
"dynamic": "node --experimental-worker ./example/dynamic" | ||
}, | ||
@@ -25,7 +27,8 @@ "repository": { | ||
"author": "mokuo", | ||
"license": "GPL-3.0", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/SUCHMOKUO/node-worker-threads-pool/issues" | ||
}, | ||
"homepage": "https://github.com/SUCHMOKUO/node-worker-threads-pool#readme" | ||
"homepage": "https://github.com/SUCHMOKUO/node-worker-threads-pool#readme", | ||
"dependencies": {} | ||
} |
143
README.md
# node-worker-threads-pool | ||
[![](https://img.shields.io/npm/v/node-worker-threads-pool.svg)](https://www.npmjs.com/package/node-worker-threads-pool) | ||
![](https://img.shields.io/badge/dependencies-none-brightgreen.svg) | ||
![](https://img.shields.io/npm/dt/node-worker-threads-pool.svg) | ||
![](https://img.shields.io/npm/l/node-worker-threads-pool.svg) | ||
Simple worker threads pool using Node's worker_threads module. | ||
@@ -7,3 +13,3 @@ | ||
1. This module can only run in Node.js. | ||
2. Since Node's worker_threads module is still in stage of **Experimental**, this module can be accessed only if the --experimental-worker flag is added. | ||
2. Since Node's worker_threads module is still in stage of **Experimental**, this module can be accessed ~~only if the `--experimental-worker` flag is added.~~, if node.js version is above 11.7.0, worker api is exposed by default. | ||
@@ -16,7 +22,30 @@ ## Installation | ||
## Example | ||
## API | ||
## `Class: StaticPool` | ||
Instance of StaticPool is a threads pool with static task provided. | ||
### `new StaticPool(opt)` | ||
- `opt` | ||
- `size` `<number>` Number of workers in this pool. | ||
- `task` `<string | function>` Static task to do. It can be a absolute path of worker file or a function. **Notice: If task is a function, you can not use closure in it! If you do want to use external data in the function, you can use workerData to pass some [cloneable data](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm).** | ||
- `workerData` `<any>` [Cloneable data](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) you want to access in task function. eg. use `workerData[property]` in task function to access the data you passed. | ||
### `staticPool.exec(param)` | ||
- `param` - The param your worker script or task function need. | ||
- Returns: `<Promise>` | ||
Choose one idle worker in the pool to execute your heavy task with the param you provided. The Promise is resolved with the result. | ||
### `staticPool.destroy()` | ||
Call `worker.terminate()` for every worker in the pool and release them. | ||
### Example (with worker file) | ||
### Run the example | ||
``` | ||
npm run example | ||
npm run static-file | ||
``` | ||
@@ -52,8 +81,11 @@ | ||
```js | ||
const Pool = require('node-worker-threads-pool'); | ||
const { StaticPool } = require('node-worker-threads-pool'); | ||
const filePath = 'absolute/path/to/your/worker/script'; | ||
const num = 4; // The number of workers in this pool. | ||
const pool = new Pool(filePath, num); | ||
const pool = new StaticPool({ | ||
size: 4, | ||
task: filePath | ||
}); | ||
for (let i = 0; i < 20; i++) { | ||
@@ -73,22 +105,101 @@ (async () => { | ||
## API | ||
### Example (with task function) | ||
### `new Pool(filePath, num)` | ||
### Run the example | ||
``` | ||
npm run static-function | ||
``` | ||
- `filePath` - The absolute path of your worker.js file. | ||
- `num` - The number of the workers in your pool. | ||
### In the main.js : | ||
```js | ||
const { StaticPool } = require('node-worker-threads-pool'); | ||
### `pool.exec(data)` | ||
const pool = new StaticPool({ | ||
size: 4, | ||
task: function(n) { | ||
const num = workerData.num; | ||
for (let i = 0; i < num; i++) { | ||
n += i; | ||
} | ||
return n; | ||
}, | ||
workerData: { | ||
num: 1 << 30 | ||
} | ||
}); | ||
- `data` - The data your worker script need. | ||
for (let i = 0; i < 20; i++) { | ||
(async () => { | ||
const res = await pool.exec(i); | ||
console.log(`result${i}:`, res); | ||
})(); | ||
} | ||
``` | ||
## `Class: DynamicPool` | ||
Instance of DynamicPool is a threads pool executes dynamic task function provided every call. | ||
### `new DynamicPool(size)` | ||
- `size` `<number>` Number of workers in this pool. | ||
### `dynamicPool.exec(opt)` | ||
- `opt` | ||
- `task` `<function>` Function as a task to do. **Notice: You can not use closure in task function! If you do want to use external data in the function, you can use workerData to pass some [cloneable data](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm).** | ||
- `workerData` `<any>` [Cloneable data](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) you want to access in task function. eg. use `workerData[property]` in task function to access the data you passed. | ||
- Returns: `<Promise>` | ||
Choose one idle worker in the pool to execute your heavy task with the data you provided. The Promise is resolved with the result your worker generated. | ||
Choose one idle worker in the pool to execute your task function. The Promise is resolved with the result your task returned. | ||
### `pool.destroy()` | ||
### `dynamicPool.destroy()` | ||
Call `worker.terminate()` for every worker in the pool and release them. | ||
## License | ||
### Example | ||
node-worker-threads-pool is licensed under the GNU General Public License v3 (GPL-3) (http://www.gnu.org/copyleft/gpl.html). | ||
### Run the example | ||
``` | ||
npm run dynamic | ||
``` | ||
### In the main.js : | ||
```js | ||
const { DynamicPool } = require('node-worker-threads-pool'); | ||
const pool = new DynamicPool(4); | ||
function task1() { | ||
// something heavy. | ||
} | ||
function task2() { | ||
// something heavy too. | ||
} | ||
// execute task1 | ||
(async () => { | ||
const res = await pool.exec({ | ||
task: task1, | ||
workerData: { | ||
... // some data | ||
} | ||
}); | ||
console.log(res); | ||
})(); | ||
// execute task2 | ||
(async () => { | ||
const res = await pool.exec({ | ||
task: task2, | ||
workerData: { | ||
... // some data | ||
} | ||
}); | ||
console.log(res); | ||
})(); | ||
``` |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Copyleft License
License(Experimental) Copyleft license information was found.
Found 1 instance in 1 package
Non-permissive License
License(Experimental) A license not known to be considered permissive was found.
Found 1 instance in 1 package
9
0
100
231
201
13759
1