Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Use fixed queue #555

Merged
merged 49 commits into from
May 19, 2024
Merged
Show file tree
Hide file tree
Changes from 44 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
3091f34
Add nodejs fixed_queue implementation
JaoodxD May 4, 2024
141fdb6
Use Task and TaskQueue interfaces in fixed-queue
JaoodxD May 4, 2024
bb347a3
Implement removal from queue
JaoodxD May 4, 2024
6ecc454
Add basic tests for fixed-queue
JaoodxD May 4, 2024
532a393
Add simple benchmark with fixed-queue as custom queue
JaoodxD May 4, 2024
5d6aaa6
Replace return with assertion to match original queue behavior
JaoodxD May 5, 2024
bda430c
Improve size calculation algorithm
JaoodxD May 5, 2024
d248503
Mention original fixed_queue implementation
JaoodxD May 5, 2024
811a952
Merge branch 'current' into use-fixed-queue
metcoder95 May 6, 2024
a6cab0a
Use old-style underscore private fields for best perforamnce with cur…
JaoodxD May 8, 2024
a291328
Expose current default taskQueue
JaoodxD May 8, 2024
8501041
Add benchmarks
JaoodxD May 8, 2024
90d46d0
Merge branch 'use-fixed-queue' of github.com:JaoodxD/piscina into use…
JaoodxD May 8, 2024
4475221
Merge branch 'current' into use-fixed-queue
metcoder95 May 9, 2024
b616d43
Expose `ArrayTaskQueue` and `FixedQueue` for named imports in commonjs
JaoodxD May 9, 2024
aa6e6e1
Use exposed queues
JaoodxD May 9, 2024
107d4a2
Optimize queue size accounting
JaoodxD May 9, 2024
9fa2bb4
Mention FixedQueue in docs
JaoodxD May 9, 2024
c0707d8
Add test case for issue with FixedQueue
JaoodxD May 9, 2024
4c00de3
Update tests for FixedQueue
JaoodxD May 14, 2024
5c575eb
Fix bug with removing elements from queue
JaoodxD May 14, 2024
aefcc95
Remove unused capacity property
JaoodxD May 14, 2024
bd776c5
Fix emptying head with remove lead to wrong isEmpty behavior
JaoodxD May 14, 2024
d5f2f77
Add nodejs fixed_queue implementation
JaoodxD May 4, 2024
7a5ab6b
Use Task and TaskQueue interfaces in fixed-queue
JaoodxD May 4, 2024
55dcebd
Implement removal from queue
JaoodxD May 4, 2024
0678138
Add basic tests for fixed-queue
JaoodxD May 4, 2024
f4704ce
Add simple benchmark with fixed-queue as custom queue
JaoodxD May 4, 2024
31953de
Replace return with assertion to match original queue behavior
JaoodxD May 5, 2024
ab95b36
Improve size calculation algorithm
JaoodxD May 5, 2024
897b620
Mention original fixed_queue implementation
JaoodxD May 5, 2024
6d0c137
Use old-style underscore private fields for best perforamnce with cur…
JaoodxD May 8, 2024
737cb5c
Expose current default taskQueue
JaoodxD May 8, 2024
80b41f9
Add benchmarks
JaoodxD May 8, 2024
1117bc4
Expose `ArrayTaskQueue` and `FixedQueue` for named imports in commonjs
JaoodxD May 9, 2024
dc69b13
Use exposed queues
JaoodxD May 9, 2024
aa78e18
Optimize queue size accounting
JaoodxD May 9, 2024
906df6e
Mention FixedQueue in docs
JaoodxD May 9, 2024
fc2e1ea
Add test case for issue with FixedQueue
JaoodxD May 9, 2024
dd8b9bb
Update tests for FixedQueue
JaoodxD May 14, 2024
395e630
Fix bug with removing elements from queue
JaoodxD May 14, 2024
ab45024
Remove unused capacity property
JaoodxD May 14, 2024
51b7df6
Fix emptying head with remove lead to wrong isEmpty behavior
JaoodxD May 14, 2024
8e9750c
Merge branch 'use-fixed-queue' of github.com:JaoodxD/piscina into use…
JaoodxD May 14, 2024
57988f4
Update README.md
JaoodxD May 14, 2024
a75fd76
Update README.md
JaoodxD May 14, 2024
fa84b3c
Update README.md
JaoodxD May 14, 2024
452feb2
Split benchmark scripts into queuetask only related and piscina related
JaoodxD May 14, 2024
f8d8f4f
Add tests of integration fixed-queue with Piscina
JaoodxD May 14, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,56 @@ options on to the custom `TaskQueue` implementation. (Note that because the
queue options are set as a property on the task, tasks with queue
options cannot be submitted as JavaScript primitives).

**New:** As of the next major release, Piscina introduces the `FixedQueue`, a more performant task queue implementation based on [`FixedQueue`](https://github.com/nodejs/node/blob/de7b37880f5a541d5f874c1c2362a65a4be76cd0/lib/internal/fixed_queue.js) from Node.Js project.
JaoodxD marked this conversation as resolved.
Show resolved Hide resolved

Here are some benchmarks to compare new `FixedQueue` with `ArrayTaskQueue` (current default). The benchmarks demonstrate substantial improvements in push and shift operations, especially with larger queue sizes.
```
Queue size = 1000
┌─────────┬─────────────────────────────────────────┬───────────┬────────────────────┬──────────┬─────────┐
│ (index) │ Task Name │ ops/sec │ Average Time (ns) │ Margin │ Samples │
├─────────┼─────────────────────────────────────────┼───────────┼────────────────────┼──────────┼─────────┤
│ 0 │ 'ArrayTaskQueue full push + full shift' │ '9 692' │ 103175.15463917515 │ '±0.80%' │ 970 │
│ 1 │ 'FixedQueue full push + full shift' │ '131 879' │ 7582.696390658352 │ '±1.81%' │ 13188 │
└─────────┴─────────────────────────────────────────┴───────────┴────────────────────┴──────────┴─────────┘

Queue size = 100_000
┌─────────┬─────────────────────────────────────────┬─────────┬────────────────────┬──────────┬─────────┐
│ (index) │ Task Name │ ops/sec │ Average Time (ns) │ Margin │ Samples │
├─────────┼─────────────────────────────────────────┼─────────┼────────────────────┼──────────┼─────────┤
│ 0 │ 'ArrayTaskQueue full push + full shift' │ '0' │ 1162376920.0000002 │ '±1.77%' │ 10 │
│ 1 │ 'FixedQueue full push + full shift' │ '1 026' │ 974328.1553396407 │ '±2.51%' │ 103 │
└─────────┴─────────────────────────────────────────┴─────────┴────────────────────┴──────────┴─────────┘
```
In terms of Piscina performance itself, using `FixedQueue` with a queue size of 100,000 queued tasks can result in up to 6 times faster execution times.

Users can import `FixedQueue` from the `Piscina` package and pass it as the `taskQueue` option to leverage its benefits.


### Using FixedQueue Example
JaoodxD marked this conversation as resolved.
Show resolved Hide resolved

Here's an example of how to use the `FixedQueue`:

```js
const { Piscina, FixedQueue } = require('piscina');
const { resolve } = require('path');

// Create a Piscina pool with FixedQueue
const piscina = new Piscina({
filename: resolve(__dirname, 'worker.js'),
taskQueue: new FixedQueue()
});

// Submit tasks to the pool
for (let i = 0; i < 10; i++) {
piscina.runTask({ data: i }).then((result) => {
console.log(result);
}).catch((error) => {
console.error(error);
});
}
```
In this example, we import `FixedQueue` from the `piscina` package and use it as the `taskQueue` option when creating a new Piscina pool. This allows users to take advantage of the performance improvements offered by `FixedQueue` before it becomes the default task queue implementation.
JaoodxD marked this conversation as resolved.
Show resolved Hide resolved

## Current Limitations (Things we're working on / would love help with)

* Improved Documentation
Expand Down
42 changes: 42 additions & 0 deletions benchmark/piscina-queue-comparison.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const { Bench } = require('tinybench');
const { Piscina, FixedQueue, ArrayTaskQueue } = require('..');
const { resolve } = require('node:path');

const QUEUE_SIZE = 100_000;

const bench = new Bench({ time: 100 });

bench
.add('Piscina with ArrayTaskQueue', async () => {
const queue = new ArrayTaskQueue();
const pool = new Piscina({
filename: resolve(__dirname, 'fixtures/add.js'),
taskQueue: queue
});
const tasks = [];
for (let i = 0; i < QUEUE_SIZE; i++) {
tasks.push(pool.runTask({ a: 4, b: 6 }));
}
await Promise.all(tasks);
await pool.destroy();
})
.add('Piscina with FixedQueue', async () => {
const queue = new FixedQueue();
const pool = new Piscina({
filename: resolve(__dirname, 'fixtures/add.js'),
taskQueue: queue
});
const tasks = [];
for (let i = 0; i < QUEUE_SIZE; i++) {
tasks.push(pool.runTask({ a: 4, b: 6 }));
}
await Promise.all(tasks);
await pool.destroy();
});

(async () => {
await bench.warmup();
await bench.run();

console.table(bench.table());
})();
33 changes: 33 additions & 0 deletions benchmark/queue-comparison.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const { Bench } = require('tinybench');
const { ArrayTaskQueue, FixedQueue } = require('..');

const QUEUE_SIZE = 100_000;

const bench = new Bench({ time: 100 });

bench
.add('ArrayTaskQueue full push + full shift', async () => {
const queue = new ArrayTaskQueue();
for (let i = 0; i < QUEUE_SIZE; i++) {
queue.push(i);
}
for (let i = 0; i < QUEUE_SIZE; i++) {
queue.shift();
}
})
.add('FixedQueue full push + full shift', async () => {
const queue = new FixedQueue();
for (let i = 0; i < QUEUE_SIZE; i++) {
queue.push(i);
}
for (let i = 0; i < QUEUE_SIZE; i++) {
queue.shift();
}
});

(async () => {
await bench.warmup();
await bench.run();

console.table(bench.table());
})();
33 changes: 33 additions & 0 deletions benchmark/simple-benchmark-fixed-queue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
'use strict';
const { Piscina, FixedQueue } = require('..');

const { resolve } = require('path');

async function simpleBenchmark ({ duration = 10000 } = {}) {
const pool = new Piscina({
filename: resolve(__dirname, 'fixtures/add.js'),
taskQueue: new FixedQueue()
});
let done = 0;

const results = [];
const start = process.hrtime.bigint();
while (pool.queueSize === 0) {
results.push(scheduleTasks());
}

async function scheduleTasks () {
while ((process.hrtime.bigint() - start) / 1_000_000n < duration) {
await pool.runTask({ a: 4, b: 6 });
done++;
}
}

await Promise.all(results);

return done / duration * 1e3;
}

simpleBenchmark().then((opsPerSecond) => {
console.log(`opsPerSecond: ${opsPerSecond} (with FixedQueue as taskQueue)`);
});
2 changes: 1 addition & 1 deletion benchmark/simple-benchmark.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ async function simpleBenchmark ({ duration = 10000 } = {}) {
}

simpleBenchmark().then((opsPerSecond) => {
console.log(`opsPerSecond: ${opsPerSecond}`);
console.log(`opsPerSecond: ${opsPerSecond} (with default taskQueue)`);
});
7 changes: 7 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@
"test": "c8 tap",
"test:ci": "npm run lint && npm run build && npm run test:coverage",
"test:coverage": "c8 --reporter=lcov tap --cov",
"prepack": "npm run build"
"prepack": "npm run build",
"bench": "npm run benchmark:piscina-default && npm run benchmark:piscina-fixed-queue && npm run benchmark:queue-comparison && npm run benchmark:piscina-comparison",
"benchmark:piscina-default": "node benchmark/simple-benchmark.js",
"benchmark:piscina-fixed-queue": "node benchmark/simple-benchmark-fixed-queue.js",
"benchmark:queue-comparison": "node benchmark/queue-comparison.js",
"benchmark:piscina-comparison": "node benchmark/piscina-queue-comparison.js"
metcoder95 marked this conversation as resolved.
Show resolved Hide resolved
},
"repository": {
"type": "git",
Expand Down Expand Up @@ -44,6 +49,7 @@
"snazzy": "^9.0.0",
"standardx": "^7.0.0",
"tap": "^16.3.7",
"tinybench": "^2.8.0",
"ts-node": "^10.9.2",
"typescript": "5.4.5"
},
Expand Down
Loading