From 9ac6dcb87a44d0e4c6ee24d3d4bbe97ff69d1940 Mon Sep 17 00:00:00 2001 From: JaoodxD Date: Mon, 13 Mar 2023 16:07:56 +0200 Subject: [PATCH 01/15] add performant queue implementation --- lib/queue.js | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 lib/queue.js diff --git a/lib/queue.js b/lib/queue.js new file mode 100644 index 0000000..943de93 --- /dev/null +++ b/lib/queue.js @@ -0,0 +1,31 @@ +'use strict'; + +class Queue { + constructor() { + this.elements = []; + this.offset = 0; + } + + push(...element) { + this.elements.push(...element); + return this; + } + + shift() { + if (this.length === 0) return null; + const first = this.elements[this.offset]; + this.offset++; + + if (this.offset * 2 < this.elements.length) return first; + + this.elements = this.elements.slice(this.offset); + this.offset = 0; + return first; + } + + get length() { + return this.elements.length - this.offset; + } +} + +module.exports = Queue; From 50df4c9f2eb79263c2f4111c63e8354c963a8baa Mon Sep 17 00:00:00 2001 From: JaoodxD Date: Mon, 13 Mar 2023 16:17:00 +0200 Subject: [PATCH 02/15] fix newline format --- lib/queue.js | 62 ++++++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/lib/queue.js b/lib/queue.js index 943de93..fb78e20 100644 --- a/lib/queue.js +++ b/lib/queue.js @@ -1,31 +1,31 @@ -'use strict'; - -class Queue { - constructor() { - this.elements = []; - this.offset = 0; - } - - push(...element) { - this.elements.push(...element); - return this; - } - - shift() { - if (this.length === 0) return null; - const first = this.elements[this.offset]; - this.offset++; - - if (this.offset * 2 < this.elements.length) return first; - - this.elements = this.elements.slice(this.offset); - this.offset = 0; - return first; - } - - get length() { - return this.elements.length - this.offset; - } -} - -module.exports = Queue; +'use strict'; + +class Queue { + constructor() { + this.elements = []; + this.offset = 0; + } + + push(...element) { + this.elements.push(...element); + return this; + } + + shift() { + if (this.length === 0) return null; + const first = this.elements[this.offset]; + this.offset++; + + if (this.offset * 2 < this.elements.length) return first; + + this.elements = this.elements.slice(this.offset); + this.offset = 0; + return first; + } + + get length() { + return this.elements.length - this.offset; + } +} + +module.exports = Queue; From 86e7e151e0f263e3756cbcfc63b53bb6fab7a902 Mon Sep 17 00:00:00 2001 From: JaoodxD Date: Mon, 13 Mar 2023 16:33:00 +0200 Subject: [PATCH 03/15] add iterator to match array spreading behavior --- lib/queue.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/queue.js b/lib/queue.js index fb78e20..ab2b3a4 100644 --- a/lib/queue.js +++ b/lib/queue.js @@ -26,6 +26,12 @@ class Queue { get length() { return this.elements.length - this.offset; } + + *[Symbol.iterator]() { + for (let i = this.offset; i < this.length; i++) { + yield this.elements[i]; + } + } } module.exports = Queue; From 8963a736b1f3e9549e6705e88829e31652717a47 Mon Sep 17 00:00:00 2001 From: JaoodxD Date: Mon, 13 Mar 2023 16:34:52 +0200 Subject: [PATCH 04/15] update all array queues to use implemented performant queue --- web-locks.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/web-locks.js b/web-locks.js index 7283d33..8f5b81c 100644 --- a/web-locks.js +++ b/web-locks.js @@ -1,6 +1,7 @@ 'use strict'; const { EventEmitter } = require('events'); +const Queue = require('./lib/queue'); const threads = require('worker_threads'); const { isMainThread, parentPort } = threads; const isWorkerThread = !isMainThread; @@ -10,11 +11,13 @@ const UNLOCKED = 1; let locks = null; // LockManager instance +const testQeueue = new Queue(); + class Lock { constructor(name, mode = 'exclusive', buffer = null) { this.name = name; this.mode = mode; // 'exclusive' or 'shared' - this.queue = []; + this.queue = new Queue(); this.owner = false; this.trying = false; this.buffer = buffer ? buffer : new SharedArrayBuffer(4); @@ -57,8 +60,8 @@ class Lock { class LockManagerSnapshot { constructor(resources) { - const held = []; - const pending = []; + const held = new Queue(); + const pending = new Queue(); this.held = held; this.pending = pending; From 2dfaa8d00519aa3e0559ab9cc99720f0581b53b6 Mon Sep 17 00:00:00 2001 From: JaoodxD Date: Mon, 13 Mar 2023 16:38:46 +0200 Subject: [PATCH 05/15] remove unnecessary code --- web-locks.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/web-locks.js b/web-locks.js index 8f5b81c..b2c023d 100644 --- a/web-locks.js +++ b/web-locks.js @@ -11,8 +11,6 @@ const UNLOCKED = 1; let locks = null; // LockManager instance -const testQeueue = new Queue(); - class Lock { constructor(name, mode = 'exclusive', buffer = null) { this.name = name; From cbc3dfb55a16592010ae1a0ab33a98b8b9752350 Mon Sep 17 00:00:00 2001 From: JaoodxD Date: Mon, 13 Mar 2023 17:07:03 +0200 Subject: [PATCH 06/15] add queue performance test --- test/queue-performance.js | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 test/queue-performance.js diff --git a/test/queue-performance.js b/test/queue-performance.js new file mode 100644 index 0000000..512c8b1 --- /dev/null +++ b/test/queue-performance.js @@ -0,0 +1,35 @@ +'use strict'; + +const assert = require('node:assert/strict'); +const { performance } = require('node:perf_hooks'); +const Queue = require('../lib/queue'); + +const simpleQueueBench = (queueClass) => { + const queue = new queueClass(); + let sum = 0; + + const timeStart = performance.now(); + for (let i = 0; i < 100_000; i++) { + queue.push(() => i); + } + for (let i = 0; i < 100_000; i++) { + sum += queue.shift()(); + } + const timeEnd = performance.now(); + + const execTime = timeEnd - timeStart; + return { sum, execTime }; +}; + +module.exports = async () => { + const testedClasses = [Array, Queue]; + + const [arrayResult, queueResult] = testedClasses.map(simpleQueueBench); + const { sum: arraySum, execTime: arrayExecTime } = arrayResult; + const { sum: queueSum, execTime: queueExecTime } = queueResult; + + const isQueueFaster = arrayExecTime > queueExecTime; + + assert.strictEqual(queueSum, arraySum); + assert.strictEqual(isQueueFaster, true); +}; From 440f17df7c35c9c82de3d05a434352a8e2710112 Mon Sep 17 00:00:00 2001 From: JaoodxD Date: Mon, 13 Mar 2023 17:07:21 +0200 Subject: [PATCH 07/15] add queue perf test --- test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test.js b/test.js index 8f48423..7f5183b 100644 --- a/test.js +++ b/test.js @@ -8,6 +8,7 @@ const tests = [ 'deadlock', 'recursive-deadlock', 'thread-main', + 'queue-performance' ]; (async () => { From 1cae25d32154a63df181fe0df3cff793389cfd60 Mon Sep 17 00:00:00 2001 From: JaoodxD Date: Mon, 13 Mar 2023 17:08:47 +0200 Subject: [PATCH 08/15] fix prettify --- test.js | 2 +- test/queue-performance.js | 70 +++++++++++++++++++-------------------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/test.js b/test.js index 7f5183b..9ee171e 100644 --- a/test.js +++ b/test.js @@ -8,7 +8,7 @@ const tests = [ 'deadlock', 'recursive-deadlock', 'thread-main', - 'queue-performance' + 'queue-performance', ]; (async () => { diff --git a/test/queue-performance.js b/test/queue-performance.js index 512c8b1..60d659e 100644 --- a/test/queue-performance.js +++ b/test/queue-performance.js @@ -1,35 +1,35 @@ -'use strict'; - -const assert = require('node:assert/strict'); -const { performance } = require('node:perf_hooks'); -const Queue = require('../lib/queue'); - -const simpleQueueBench = (queueClass) => { - const queue = new queueClass(); - let sum = 0; - - const timeStart = performance.now(); - for (let i = 0; i < 100_000; i++) { - queue.push(() => i); - } - for (let i = 0; i < 100_000; i++) { - sum += queue.shift()(); - } - const timeEnd = performance.now(); - - const execTime = timeEnd - timeStart; - return { sum, execTime }; -}; - -module.exports = async () => { - const testedClasses = [Array, Queue]; - - const [arrayResult, queueResult] = testedClasses.map(simpleQueueBench); - const { sum: arraySum, execTime: arrayExecTime } = arrayResult; - const { sum: queueSum, execTime: queueExecTime } = queueResult; - - const isQueueFaster = arrayExecTime > queueExecTime; - - assert.strictEqual(queueSum, arraySum); - assert.strictEqual(isQueueFaster, true); -}; +'use strict'; + +const assert = require('node:assert/strict'); +const { performance } = require('node:perf_hooks'); +const Queue = require('../lib/queue'); + +const simpleQueueBench = (queueClass) => { + const queue = new queueClass(); + let sum = 0; + + const timeStart = performance.now(); + for (let i = 0; i < 100_000; i++) { + queue.push(() => i); + } + for (let i = 0; i < 100_000; i++) { + sum += queue.shift()(); + } + const timeEnd = performance.now(); + + const execTime = timeEnd - timeStart; + return { sum, execTime }; +}; + +module.exports = async () => { + const testedClasses = [Array, Queue]; + + const [arrayResult, queueResult] = testedClasses.map(simpleQueueBench); + const { sum: arraySum, execTime: arrayExecTime } = arrayResult; + const { sum: queueSum, execTime: queueExecTime } = queueResult; + + const isQueueFaster = arrayExecTime > queueExecTime; + + assert.strictEqual(queueSum, arraySum); + assert.strictEqual(isQueueFaster, true); +}; From 7fe2b464c8b26086267dacc087f863d44dc0be73 Mon Sep 17 00:00:00 2001 From: JaoodxD Date: Mon, 13 Mar 2023 17:10:48 +0200 Subject: [PATCH 09/15] fix constructor name and number delimeter --- test/queue-performance.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/queue-performance.js b/test/queue-performance.js index 60d659e..919e707 100644 --- a/test/queue-performance.js +++ b/test/queue-performance.js @@ -4,15 +4,15 @@ const assert = require('node:assert/strict'); const { performance } = require('node:perf_hooks'); const Queue = require('../lib/queue'); -const simpleQueueBench = (queueClass) => { - const queue = new queueClass(); +const simpleQueueBench = (QueueClass) => { + const queue = new QueueClass(); let sum = 0; const timeStart = performance.now(); - for (let i = 0; i < 100_000; i++) { + for (let i = 0; i < 100000; i++) { queue.push(() => i); } - for (let i = 0; i < 100_000; i++) { + for (let i = 0; i < 100000; i++) { sum += queue.shift()(); } const timeEnd = performance.now(); From 96f0f34ea5198811a2ee6753d445f25545d33a9d Mon Sep 17 00:00:00 2001 From: JaoodxD Date: Tue, 14 Mar 2023 02:38:54 +0200 Subject: [PATCH 10/15] update benchmark to make iteration count configurable --- test/queue-performance.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/queue-performance.js b/test/queue-performance.js index 919e707..ad21c1e 100644 --- a/test/queue-performance.js +++ b/test/queue-performance.js @@ -6,13 +6,14 @@ const Queue = require('../lib/queue'); const simpleQueueBench = (QueueClass) => { const queue = new QueueClass(); + const iterations = 100000; let sum = 0; const timeStart = performance.now(); - for (let i = 0; i < 100000; i++) { + for (let i = 0; i < iterations; i++) { queue.push(() => i); } - for (let i = 0; i < 100000; i++) { + for (let i = 0; i < iterations; i++) { sum += queue.shift()(); } const timeEnd = performance.now(); @@ -21,6 +22,8 @@ const simpleQueueBench = (QueueClass) => { return { sum, execTime }; }; +const percentDifference = (n1, n2) => (Math.abs(n1) / n2); + module.exports = async () => { const testedClasses = [Array, Queue]; @@ -28,6 +31,11 @@ module.exports = async () => { const { sum: arraySum, execTime: arrayExecTime } = arrayResult; const { sum: queueSum, execTime: queueExecTime } = queueResult; + console.log({ + improveRate: percentDifference(arrayExecTime, queueExecTime), + arrayExecTime, + queueExecTime + }); const isQueueFaster = arrayExecTime > queueExecTime; assert.strictEqual(queueSum, arraySum); From 15868043c4d25ba987b573a58fc8e1f4b30adaab Mon Sep 17 00:00:00 2001 From: JaoodxD Date: Tue, 14 Mar 2023 02:42:43 +0200 Subject: [PATCH 11/15] remove unnecessary std output --- test/queue-performance.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/test/queue-performance.js b/test/queue-performance.js index ad21c1e..fd4a525 100644 --- a/test/queue-performance.js +++ b/test/queue-performance.js @@ -22,8 +22,6 @@ const simpleQueueBench = (QueueClass) => { return { sum, execTime }; }; -const percentDifference = (n1, n2) => (Math.abs(n1) / n2); - module.exports = async () => { const testedClasses = [Array, Queue]; @@ -31,11 +29,6 @@ module.exports = async () => { const { sum: arraySum, execTime: arrayExecTime } = arrayResult; const { sum: queueSum, execTime: queueExecTime } = queueResult; - console.log({ - improveRate: percentDifference(arrayExecTime, queueExecTime), - arrayExecTime, - queueExecTime - }); const isQueueFaster = arrayExecTime > queueExecTime; assert.strictEqual(queueSum, arraySum); From fa34b3a7f636e7544156eeea2f6907aaee1b0fa4 Mon Sep 17 00:00:00 2001 From: JaoodxD Date: Mon, 27 Mar 2023 19:02:00 +0300 Subject: [PATCH 12/15] add `lib/queue.js` to package files list --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fc12466..c078683 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "email": "timur.shemsedinov@gmail.com" }, "main": "web-locks.js", - "files": [], + "files": ["./lib/queue.js"], "engines": { "node": ">=11.0.0" }, From 40cfe0b8c0262d8fba5896a9a073f079c90245fd Mon Sep 17 00:00:00 2001 From: Maksym Shenderuk <39469154+JaoodxD@users.noreply.github.com> Date: Thu, 30 Mar 2023 09:20:13 +0300 Subject: [PATCH 13/15] Update `Queue` import to make it explicit Co-authored-by: Timur Shemsedinov --- web-locks.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web-locks.js b/web-locks.js index b2c023d..2f4d87b 100644 --- a/web-locks.js +++ b/web-locks.js @@ -1,7 +1,7 @@ 'use strict'; const { EventEmitter } = require('events'); -const Queue = require('./lib/queue'); +const Queue = require('./lib/queue.js'); const threads = require('worker_threads'); const { isMainThread, parentPort } = threads; const isWorkerThread = !isMainThread; From 3c6876195a8c39f7dfb8c13d158db41a66ffafe8 Mon Sep 17 00:00:00 2001 From: JaoodxD Date: Thu, 30 Mar 2023 09:38:11 +0300 Subject: [PATCH 14/15] Update `Queue` import to make it explicit --- test/queue-performance.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/queue-performance.js b/test/queue-performance.js index fd4a525..daa66e4 100644 --- a/test/queue-performance.js +++ b/test/queue-performance.js @@ -2,7 +2,7 @@ const assert = require('node:assert/strict'); const { performance } = require('node:perf_hooks'); -const Queue = require('../lib/queue'); +const Queue = require('../lib/queue.js'); const simpleQueueBench = (QueueClass) => { const queue = new QueueClass(); From 41f2d428f0c75c1e72e653ae4d7c2db9cb9c2ac0 Mon Sep 17 00:00:00 2001 From: Maksym Shenderuk Date: Tue, 3 Oct 2023 14:34:59 +0300 Subject: [PATCH 15/15] Fix `lib/queue.js` not being part of the installable package --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c078683..cb9a3a8 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "email": "timur.shemsedinov@gmail.com" }, "main": "web-locks.js", - "files": ["./lib/queue.js"], + "files": ["lib/queue.js"], "engines": { "node": ">=11.0.0" },