{"id":338750,"date":"2022-09-26T09:00:37","date_gmt":"2022-09-26T09:00:37","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=338750"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=338750","title":{"rendered":"<span>\u041f\u0440\u0438\u0440\u0443\u0447\u0430\u0435\u043c \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u044c \u0432 Node.js (\u0447\u0430\u0441\u0442\u044c 2: \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u043a\u0430\u043d\u0430\u043b\u044b \u0438 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440)<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/c31\/527\/94e\/c3152794ecd0e4392c7b7b23182c7d67.jpeg\" alt=\"Multithreading \u043a\u0430\u043a \u043e\u043d \u0435\u0441\u0442\u044c\" title=\"Multithreading \u043a\u0430\u043a \u043e\u043d \u0435\u0441\u0442\u044c\" width=\"2000\" height=\"1200\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c31\/527\/94e\/c3152794ecd0e4392c7b7b23182c7d67.jpeg\" data-blurred=\"true\"\/><figcaption>Multithreading \u043a\u0430\u043a \u043e\u043d \u0435\u0441\u0442\u044c<\/figcaption><\/figure>\n<p>\u0412 <a href=\"\/ru\/post\/689144\/\">\u043f\u0435\u0440\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0441\u0442\u0430\u0442\u044c\u0438<\/a> \u043c\u044b \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438\u0441\u044c \u043d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442\u0435, \u043a\u043e\u0433\u0434\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447 \u043c\u0435\u0436\u0434\u0443 \u043f\u043e\u0442\u043e\u043a\u0430\u043c\u0438 \u043f\u043e \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0443 <a href=\"https:\/\/ru.wikipedia.org\/wiki\/Round-robin_(%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC)\">Round-robin<\/a> \u043c\u044b \u0434\u043e\u0431\u0438\u043b\u0438\u0441\u044c-\u0442\u0430\u043a\u0438 \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0437\u0430 \u0441\u0447\u0435\u0442 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p>\u041d\u043e \u0432\u043e\u0442 \u043d\u0435\u043f\u0440\u0438\u044f\u0442\u043d\u043e\u0441\u0442\u044c: \u0442\u0430\u043a\u043e\u0439 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u043e\u0447\u0435\u043d\u044c <strong>\u043d\u0435\u0440\u0430\u0432\u043d\u043e\u043c\u0435\u0440\u043d\u043e \u043d\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u043f\u043e\u0442\u043e\u043a\u0438<\/strong> <strong>\u0438 \u043d\u0435 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0443\u0442\u0438\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442 \u0438\u0445<\/strong> \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 &#8212; \u043f\u043e\u043a\u0430 \u043a\u0442\u043e-\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u0430\u0438\u0432\u0430\u0435\u0442, \u0434\u0440\u0443\u0433\u043e\u0439 \u0443\u0436\u0435 \u043a\u043e\u043f\u0438\u0442 \u043e\u0447\u0435\u0440\u0435\u0434\u044c. \u041a\u0430\u043a \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u043e\u0431\u043e\u0439\u0442\u0438?<\/p>\n<h3>\u041f\u0443\u043b \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u0438 \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0437\u0430\u0434\u0430\u0447<\/h3>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0432\u043c\u0435\u0441\u0442\u043e &#171;\u0437\u0430\u043f\u0438\u0445\u0438\u0432\u0430\u043d\u0438\u044f&#187; \u0437\u0430\u0434\u0430\u0447\u0438 \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c <strong>\u043e\u0431\u0449\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c<\/strong> \u0434\u043b\u044f \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e <strong>\u043f\u0443\u043b\u0430 \u043f\u043e\u0442\u043e\u043a\u043e\u0432<\/strong>:<\/p>\n<ul>\n<li>\n<p>\u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0437\u0430\u0434\u0430\u0447\u0438 \u043e\u0442\u0434\u0430\u0435\u043c \u0435\u0435 \u043f\u0435\u0440\u0432\u043e\u043c\u0443 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u043c\u0443 \u043f\u043e\u0442\u043e\u043a\u0443 \u0438\u043b\u0438 \u0441\u0442\u0430\u0432\u0438\u043c \u0432 \u043e\u0431\u0449\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u043a\u043e\u0433\u0434\u0430 \u0442\u0430\u043a\u0438\u0445 \u043d\u0435\u0442;<\/p>\n<\/li>\n<li>\n<p>\u043f\u0440\u0438 \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u0438 \u043f\u043e\u0442\u043e\u043a\u0430 \u0441\u0440\u0430\u0437\u0443 \u0434\u0430\u0435\u043c \u0435\u043c\u0443 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443 \u0438\u0437 \u043e\u0447\u0435\u0440\u0435\u0434\u0438.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0442\u0430\u043a\u043e\u0439 \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438 \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u043c\u0430\u0441\u0441\u0438\u0432. \u041d\u043e \u043b\u0443\u0447\u0448\u0435 \u043d\u0435 \u0441\u0442\u043e\u0438\u0442 \u0438\u0437-\u0437\u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 <code>Array.shift()<\/code>, \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0445 \u0432 <a href=\"\/ru\/post\/688182\/\">\u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435<\/a> &#8212; \u0442\u0430\u043a \u0447\u0442\u043e \u0432\u043e\u0437\u044c\u043c\u0435\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043a\u043e\u043b\u044c\u0446\u0435\u0432\u043e\u0433\u043e \u0431\u0443\u0444\u0435\u0440\u0430, \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u043d\u0443\u044e \u0442\u0430\u043c \u0436\u0435.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a13\/38f\/6bd\/a1338f6bdefc63eef45d1f5ed8a5c3e2.png\" alt=\"\u0421\u0445\u0435\u043c\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043e\u0431\u0449\u0435\u0439 \u043e\u0447\u0435\u0440\u0435\u0434\u044c\u044e\" title=\"\u0421\u0445\u0435\u043c\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043e\u0431\u0449\u0435\u0439 \u043e\u0447\u0435\u0440\u0435\u0434\u044c\u044e\" width=\"568\" height=\"549\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/a13\/38f\/6bd\/a1338f6bdefc63eef45d1f5ed8a5c3e2.png\"\/><figcaption>\u0421\u0445\u0435\u043c\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043e\u0431\u0449\u0435\u0439 \u043e\u0447\u0435\u0440\u0435\u0434\u044c\u044e<\/figcaption><\/figure>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u043e\u0442\u043b\u0438\u0447\u0438\u0435\u043c \u043e\u0442 \u0441\u0445\u0435\u043c\u044b \u0441 Round-robin, \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u043d\u043e\u0439 \u0432 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0447\u0430\u0441\u0442\u0438, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u043f\u0430\u0434\u0430\u043d\u0438\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u0432 \u043f\u043e\u0442\u043e\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u0433\u0434\u0430 \u043e\u043d \u0443\u0436\u0435 \u0433\u043e\u0442\u043e\u0432 \u0435\u0439 \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c\u0441\u044f, \u043f\u0440\u0438\u0447\u0435\u043c \u0441\u0440\u0430\u0437\u0443 \u043f\u0440\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439.<\/p>\n<p>\u041c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0432 \u043d\u0430\u0448\u0435\u043c \u043a\u043e\u0434\u0435 \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043d\u0435\u0432\u0435\u043b\u0438\u043a\u0438 &#8212; \u0441\u0430\u043c\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043b\u0430\u0441\u0441\u0430 <code>WorkersPool<\/code>:<\/p>\n<pre><code class=\"javascript\">\/\/ ... const EventEmitter = require('events'); class WorkersPool extends EventEmitter {   #queue;   #workersPool;   #currentWorker;   #onMessageHandler = Symbol('handler');    constructor({queue, workersPool}) {     super();      this.#queue = queue;     this.#workersPool = [...workersPool];      \/\/ \u043d\u0430\u0432\u0435\u0448\u0438\u0432\u0430\u0435\u043c \u0441\u0432\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432 \u0441\u0430\u043c\u043e\u0435 \u043d\u0430\u0447\u0430\u043b\u043e \u0446\u0435\u043f\u043e\u0447\u043a\u0438     this.#workersPool.forEach(worker => {       worker[this.#onMessageHandler] = this.#onMessage.bind(this, worker);       worker.prependListener('message', worker[this.#onMessageHandler]);     });   }    destructor() {     \/\/  \u0433\u0430\u0441\u0438\u043c \u0441\u0432\u043e\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438     this.#workersPool.forEach(worker => {       worker.off('message', worker[this.#onMessageHandler]);       delete worker[this.#onMessageHandler];     });   }    #onMessage(worker) {     \/\/ \u0435\u0441\u043b\u0438 \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u0447\u0442\u043e-\u0442\u043e \u0435\u0441\u0442\u044c - \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0432\u044b\u0437\u0432\u0430\u0432\u0448\u0435\u043c\u0443     const msg = this.#queue.shift();     if (msg) {       worker.postMessage(msg);     }     \/\/ \u0435\u0441\u043b\u0438 \u043d\u0435\u0442 - \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0435\u0433\u043e \u0436\u0434\u0430\u0442\u044c \u0432 \u043f\u0443\u043b\u0435     else {       this.#workersPool.push(worker);     }   }    postMessage(msg) {     \/\/ \u0434\u043e\u0441\u0442\u0430\u0435\u043c \u0438\u0437 \u043f\u0443\u043b\u0430 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u044b\u0439 \u0432\u043e\u0440\u043a\u0435\u0440     const worker = this.#workersPool.pop();     if (worker) {       worker.postMessage(msg);     }     else {       \/\/ \u0435\u0441\u043b\u0438 \u0435\u0433\u043e \u043d\u0435\u0442 - \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u0438       this.#queue.push(msg);     }   } } \/\/ ...<\/code><\/pre>\n<p>&#8230; \u0438 \u043f\u0430\u0440\u0430 \u043c\u0435\u0441\u0442 \u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f:<\/p>\n<pre><code class=\"javascript\">\/\/ ... if (isMainThread) {   \/\/ ...   let pool; \/\/ \u044d\u0442\u043e \u043d\u0430\u0448 \u043f\u0443\u043b   process     .on('test:start', () => {       \/\/ ...       \/\/ \u043f\u0443\u043b \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u0441 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u043e\u0447\u0435\u0440\u0435\u0434\u044c\u044e       const Pow2Buffer = require('.\/Pow2Buffer');       pool = new WorkersPool({         queue : new Pow2Buffer(8, 16)       , workersPool : workers.slice(0, active)       });       \/\/ ...       messages.forEach((data, id) => {         pool.postMessage({id, data}); \/\/ \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0432\u0441\u0435 \u0432 \u043f\u0443\u043b       });     })     .on('test:end', () => {       \/\/ ...       if (active &lt; n) {         pool.destructor(); \/\/ \u0437\u0430\u0447\u0438\u0449\u0430\u0435\u043c \u043f\u043e\u0442\u043e\u043a\u0438 \u043f\u0443\u043b\u0430 \u043e\u0442 \u043d\u0430\u0448\u0438\u0445 \u043f\u043e\u0434\u043f\u0438\u0441\u043e\u043a         active++;         process.emit('test:start');       }       else {         process.exit();       }     }); \/\/ ...<\/code><\/pre>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0442\u0435\u0441\u0442\u043e\u0432<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">const {   Worker , isMainThread , parentPort } = require('node:worker_threads');  const {   randomBytes , createHash } = require('node:crypto');  const hrtime = process.hrtime.bigint;  const EventEmitter = require('events'); class WorkersPool extends EventEmitter {   #queue;   #workersPool;   #currentWorker;   #onMessageHandler = Symbol('handler');    constructor({queue, workersPool}) {     super();      this.#queue = queue;     this.#workersPool = [...workersPool];      \/\/ \u043d\u0430\u0432\u0435\u0448\u0438\u0432\u0430\u0435\u043c \u0441\u0432\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432 \u0441\u0430\u043c\u043e\u0435 \u043d\u0430\u0447\u0430\u043b\u043e \u0446\u0435\u043f\u043e\u0447\u043a\u0438     this.#workersPool.forEach(worker => {       worker[this.#onMessageHandler] = this.#onMessage.bind(this, worker);       worker.prependListener('message', worker[this.#onMessageHandler]);     });   }    destructor() {     \/\/  \u0433\u0430\u0441\u0438\u043c \u0441\u0432\u043e\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438     this.#workersPool.forEach(worker => {       worker.off('message', worker[this.#onMessageHandler]);       delete worker[this.#onMessageHandler];     });   }    #onMessage(worker) {     \/\/ \u0435\u0441\u043b\u0438 \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u0447\u0442\u043e-\u0442\u043e \u0435\u0441\u0442\u044c - \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0432\u044b\u0437\u0432\u0430\u0432\u0448\u0435\u043c\u0443     const msg = this.#queue.shift();     if (msg) {       worker.postMessage(msg);     }     \/\/ \u0435\u0441\u043b\u0438 \u043d\u0435\u0442 - \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0435\u0433\u043e \u0436\u0434\u0430\u0442\u044c \u0432 \u043f\u0443\u043b\u0435     else {       this.#workersPool.push(worker);     }   }    postMessage(msg) {     \/\/ \u0434\u043e\u0441\u0442\u0430\u0435\u043c \u0438\u0437 \u043f\u0443\u043b\u0430 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u044b\u0439 \u0432\u043e\u0440\u043a\u0435\u0440     const worker = this.#workersPool.pop();     if (worker) {       worker.postMessage(msg);     }     else {       \/\/ \u0435\u0441\u043b\u0438 \u0435\u0433\u043e \u043d\u0435\u0442 - \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u0438       this.#queue.push(msg);     }   } }  if (isMainThread) {   const tsg = hrtime();   const messages = Array(1 &lt;&lt; 12).fill().map(_ => randomBytes(1 &lt;&lt; 16));   console.log('generated:', Number(hrtime() - tsg)\/1e6 | 0, 'ms');    const hashes = messages.map(() => undefined);   let remain;    const workers = [];   let active = 1;   let tsh;    let pool; \/\/ \u044d\u0442\u043e \u043d\u0430\u0448 \u043f\u0443\u043b   process     .on('test:start', () => {       hashes.fill();       remain = hashes.length;            \/\/ \u043f\u0443\u043b \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u0441 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u043e\u0447\u0435\u0440\u0435\u0434\u044c\u044e       const Pow2Buffer = require('.\/Pow2Buffer');       pool = new WorkersPool({         queue : new Pow2Buffer(8, 16)       , workersPool : workers.slice(0, active)       });        \/\/ \u0444\u0438\u043a\u0441\u0438\u0440\u0443\u0435\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043d\u0430 \u043d\u0430\u0447\u0430\u043b\u043e \u0442\u0435\u0441\u0442\u0430       workers.forEach(worker => worker.eLU = worker.performance.eventLoopUtilization());       tsh = hrtime();       messages.forEach((data, id) => {         pool.postMessage({id, data});       });     })     .on('test:end', () => {       const duration = hrtime() - tsh;       workers.forEach(worker => worker.util = worker.performance.eventLoopUtilization(worker.eLU).utilization);       const avg = workers.slice(0, active).reduce((sum, worker) => sum + worker.util, 0)\/active;        console.log(         'hashed ' + active.toString().padStart(2) + ':'       , (Number(duration)\/1e6 | 0).toString().padStart(4)       , 'ms | ' + (avg * 100 | 0) + ' | '       , workers.map(           worker => (worker.util * 100 | 0).toString().padStart(2)         ).join(' ')       );        if (active &lt; n) {         pool.destructor(); \/\/ \u0437\u0430\u0447\u0438\u0449\u0430\u0435\u043c \u043f\u0443\u043b         active++;         process.emit('test:start');       }       else {         process.exit();       }     });    const n = 16;   Promise.all(     Array(n).fill().map(_ => {       return new Promise((resolve, reject) => {         const worker = new Worker(__filename);         worker           .on('online', () => resolve(worker))           .on('message', ({id, hash}) => {             hashes[id] = hash;             if (!--remain) {               process.emit('test:end');             }           });       });         })   )     .then((result) => {       workers.push(...result);       process.emit('test:start');     }); } else {   parentPort.on('message', ({id, data}) => {     parentPort.postMessage({id, hash : createHash('sha256').update(data).digest('hex')});   }); }<\/code><\/pre>\n<pre><code>generated: 278 ms hashed  1: 1449 ms | 82 |  82  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 hashed  2:  701 ms | 82 |  81 84  0  0  0  0  0  0  0  0  0  0  0  0  0  0 hashed  3:  485 ms | 81 |  78 79 85  0  0  0  0  0  0  0  0  0  0  0  0  0 hashed  4:  370 ms | 79 |  77 79 78 81  0  0  0  0  0  0  0  0  0  0  0  0 hashed  5:  347 ms | 68 |  66 64 70 69 72  0  0  0  0  0  0  0  0  0  0  0 hashed  6:  360 ms | 57 |  56 59 53 52 57 62  0  0  0  0  0  0  0  0  0  0 hashed  7:  310 ms | 54 |  54 50 54 50 56 55 58  0  0  0  0  0  0  0  0  0 hashed  8:  312 ms | 46 |  40 45 47 50 43 45 44 50  0  0  0  0  0  0  0  0 hashed  9:  311 ms | 42 |  35 42 42 44 38 41 44 57 38  0  0  0  0  0  0  0 hashed 10:  301 ms | 36 |  35 36 31 34 40 38 37 38 36 39  0  0  0  0  0  0 hashed 11:  312 ms | 32 |  27 31 32 32 29 29 37 32 35 35 30  0  0  0  0  0 hashed 12:  338 ms | 30 |  26 34 24 38 27 31 39 28 25 27 30 31  0  0  0  0 hashed 13:  321 ms | 27 |  23 24 23 26 26 24 32 30 26 28 28 31 25  0  0  0 hashed 14:  316 ms | 29 |  28 21 27 39 26 29 30 18 25 36 29 37 25 33  0  0 hashed 15:  314 ms | 26 |  24 29 28 28 18 28 28 37 17 17 30 25 27 28 32  0 hashed 16:  344 ms | 28 |  23 24 27 28 26 35 23 36 22 37 26 43 22 23 25 23<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/90b\/e14\/3a6\/90be143a62f69941d2496fed0f58e60f.png\" alt=\"Queue vs Round-Robin\" title=\"Queue vs Round-Robin\" width=\"1202\" height=\"471\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/90b\/e14\/3a6\/90be143a62f69941d2496fed0f58e60f.png\"\/><figcaption>Queue vs Round-Robin<\/figcaption><\/figure>\n<p>\u041f\u0440\u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u043d\u0435 \u043c\u0435\u043d\u044c\u0448\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u044f\u0434\u0435\u0440 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u0430 <strong>\u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0441 \u043e\u0431\u0449\u0435\u0439 \u043e\u0447\u0435\u0440\u0435\u0434\u044c\u044e \u0432\u044b\u0438\u0433\u0440\u044b\u0432\u0430\u0435\u0442<\/strong> \u043f\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043f\u0440\u0438 \u0431\u043e\u043b\u0435\u0435 \u0440\u0430\u0432\u043d\u043e\u043c\u0435\u0440\u043d\u043e\u0439 \u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043c\u0435\u043d\u044c\u0448\u0435\u0439 \u0441\u0440\u0435\u0434\u043d\u0435\u0439 \u0443\u0442\u0438\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u0442\u043e\u043a\u043e\u0432.<\/p>\n<h3>\u041a\u0430\u043d\u0430\u043b\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u0432<\/h3>\n<p>\u0412\u043f\u0440\u043e\u0447\u0435\u043c, \u0432 \u044d\u0442\u043e\u0439 \u0440\u0430\u0434\u0443\u0436\u043d\u043e\u0439 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0435 \u0435\u0441\u0442\u044c \u0438 \u0442\u043e\u043b\u0438\u043a\u0430 \u043f\u0435\u0447\u0430\u043b\u0438. \u0421\u0440\u0435\u0434\u043d\u044f\u044f \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0430 \u043f\u043e\u0442\u043e\u043a\u0430\u0445 \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u043b\u0430\u0441\u044c \u0440\u043e\u0432\u043d\u043e \u0437\u0430 \u0441\u0447\u0435\u0442 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043c\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u043c \u0438\u0445 \u0442\u0435\u043f\u0435\u0440\u044c \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c &#8212; \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0445\u043e\u0440\u043e\u0448\u043e \u044d\u0442\u043e \u0432\u0438\u0434\u043d\u043e \u043f\u0440\u0438 \u043c\u0430\u043b\u043e\u043c \u0438\u0445 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435.<\/p>\n<p>\u042d\u0442\u043e \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0435\u0442\u0441\u044f \u0442\u0435\u043c, \u0447\u0442\u043e \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043f\u043e\u0442\u043e\u043a \u0437\u0430\u043c\u0435\u0442\u043d\u043e \u0432\u044b\u0440\u043e\u0441\u043b\u0430 \u0438\u0437-\u0437\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438  \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u043f\u0440\u0438\u043a\u043b\u0430\u0434\u043d\u0443\u044e \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c, \u043d\u043e \u0438 \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c\u0441\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u043e\u0439 \u043e\u0447\u0435\u0440\u0435\u0434\u0438 &#8212; \u043a\u0430\u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c, <strong>\u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u043e\u0442\u0432\u0435\u0442<\/strong>, \u043e\u0442\u043c\u0435\u0447\u0430\u044f \u0441\u043b\u0443\u0436\u0435\u0431\u043d\u044b\u0439 \u043f\u043e\u0442\u043e\u043a \u043a\u0430\u043a \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u044b\u0439.<\/p>\n<p>\u041d\u043e \u0432\u0435\u0434\u044c \u043c\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u0442\u043e \u043c\u043e\u0436\u0435\u043c <strong>\u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u043a\u0430\u043d\u0430\u043b\u044b \u043e\u0431\u043c\u0435\u043d\u0430 \u0441 \u043f\u043e\u0442\u043e\u043a\u043e\u043c<\/strong>, \u043d\u0430 \u043a\u0430\u043d\u0430\u043b \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u043a\u0430\u043d\u0430\u043b \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u0432 \u043a\u0430\u043a \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u044b <a href=\"https:\/\/nodejs.org\/dist\/latest-v16.x\/docs\/api\/worker_threads.html#class-messagechannel\">MessageChannel<\/a>. \u0418 \u0431\u0443\u0434\u0435\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u0438\u0433\u043d\u0430\u043b \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u043f\u043e\u0442\u043e\u043a\u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u043e\u043a\u0440\u0430\u0442\u043d\u043e \u043f\u0440\u0438 <strong>\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0441\u0440\u0430\u0437\u0443 \u043f\u0430\u0447\u043a\u0438 \u0437\u0430\u0434\u0430\u0447<\/strong>, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c\u044b\u0445 \u0447\u0435\u0440\u0435\u0437 <a href=\"https:\/\/nodejs.org\/dist\/latest-v16.x\/docs\/api\/worker_threads.html#workerreceivemessageonportport\">receiveMessageOnPort<\/a>.<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f31\/9dc\/5ad\/f319dc5ad410ef54f2358779dbbcba98.png\" alt=\"\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 MessageChannel\" title=\"\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 MessageChannel\" width=\"379\" height=\"454\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f31\/9dc\/5ad\/f319dc5ad410ef54f2358779dbbcba98.png\"\/><figcaption>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 MessageChannel<\/figcaption><\/figure>\n<p>\u0421\u0445\u0435\u043c\u0430\u0442\u0438\u0447\u043d\u043e <code>MessageChannel<\/code> \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d, \u043a\u0430\u043a \u0434\u0432\u0430 \u043f\u043e\u0440\u0442\u0430, \u043e\u0434\u0438\u043d \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u0438\u0442 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c\u0443 (\u0438\u043b\u0438 \u043b\u044e\u0431\u043e\u043c\u0443 \u0434\u0440\u0443\u0433\u043e\u043c\u0443) \u043f\u043e\u0442\u043e\u043a\u0443, \u0430 \u0434\u0440\u0443\u0433\u043e\u0439 &#8212; \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u043c\u0443. \u0412 \u043a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u043d\u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u043a\u0430\u043a \u043d\u0435\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u043e \u043f\u0438\u0441\u0430\u0442\u044c, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0437\u0430 \u043d\u0438\u043c \u0441\u0442\u043e\u0438\u0442 \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u0442\u0430\u043a \u0438 \u0447\u0438\u0442\u0430\u0442\u044c \u0438\u0437 \u043d\u0435\u0433\u043e &#8212; \u043f\u043e\u043b\u0443\u0447\u0430\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0438\u043b\u0438 \u0432\u044b\u0447\u0438\u0442\u044b\u0432\u0430\u044f \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e.<\/p>\n<p>\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0439 \u043d\u0430\u043c \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u043f\u043e\u0442\u043e\u043a\u0430 <code>parentPort<\/code> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0440\u043e\u0432\u043d\u043e \u0442\u0430\u043a\u043e\u0439 \u0436\u0435 &#171;\u043f\u043e\u043b\u043e\u0432\u0438\u043d\u043a\u043e\u0439&#187; \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432 <code>Worker<\/code> \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430  <code>MessageChannel.<\/code><\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c01\/f5d\/265\/c01f5d265fc2c14683dff8bcffc1c7ed.png\" alt=\"\u0421\u0445\u0435\u043c\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u043a\u0430\u043d\u0430\u043b\u0430\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u0432\" title=\"\u0421\u0445\u0435\u043c\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u043a\u0430\u043d\u0430\u043b\u0430\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u0432\" width=\"568\" height=\"662\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c01\/f5d\/265\/c01f5d265fc2c14683dff8bcffc1c7ed.png\"\/><figcaption>\u0421\u0445\u0435\u043c\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u043a\u0430\u043d\u0430\u043b\u0430\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u0432<\/figcaption><\/figure>\n<p>\u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0433\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430, \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 \u0434\u0430\u0442\u0430-\u043f\u043e\u0440\u0442 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 \u0441\u0440\u0430\u0437\u0443 <strong>\u0431\u043b\u043e\u043a\u0430\u043c\u0438 \u0438\u0437 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0437\u0430\u0434\u0430\u0447<\/strong>, \u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043f\u043e\u0442\u043e\u043a \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u043f\u043e\u0440\u0446\u0438\u044e \u043d\u0435 \u043d\u0430 \u043a\u0430\u0436\u0434\u0443\u044e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443, \u0430 \u043f\u0440\u0438 \u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0438 \u0447\u0435\u0440\u0435\u0437 \u0441\u0438\u0433\u043d\u0430\u043b-\u043f\u043e\u0440\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e\u0431 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0432\u0441\u0435\u0433\u043e \u0431\u043b\u043e\u043a\u0430.<\/p>\n<p>\u041f\u043e\u043d\u044f\u0442\u043d\u043e, \u0447\u0442\u043e \u0435\u0441\u043b\u0438 \u0437\u0430\u0434\u0430\u0447\u0438 \u043d\u0435 \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u043e \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u044f \u0441\u0440\u0430\u0437\u0443 \u0431\u043b\u043e\u043a\u0430\u043c\u0438, \u043c\u044b \u0441\u043d\u043e\u0432\u0430 \u043c\u043e\u0436\u0435\u043c \u043a\u0430\u043a\u0438\u0435-\u0442\u043e \u0438\u0437 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u043f\u0435\u0440\u0435\u0433\u0440\u0443\u0437\u0438\u0442\u044c. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0431\u0443\u0434\u0435\u043c \u0441\u0442\u0430\u0440\u0430\u0442\u044c\u0441\u044f \u043e\u0442\u0434\u0430\u0432\u0430\u0442\u044c \u043f\u043e\u0442\u043e\u043a\u0443 \u043d\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 <strong>1\/N<\/strong> \u043e\u0442 \u043e\u0441\u0442\u0430\u044e\u0449\u0435\u0439\u0441\u044f \u0434\u043b\u0438\u043d\u044b \u043e\u0447\u0435\u0440\u0435\u0434\u0438.<\/p>\n<p>\u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0432\u043c\u0435\u0441\u0442\u043e \u043f\u0443\u043b\u0430 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u0438\u043c\u0435\u0442\u044c \u043f\u0443\u043b \u0434\u0430\u0442\u0430-\u043a\u0430\u043d\u0430\u043b\u043e\u0432 (\u0442\u043e\u0447\u043d\u0435\u0435, \u0438\u0445 \u043f\u043e\u0440\u0442\u043e\u0432) \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0443 \u043d\u0430 \u0441\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u043e\u0440\u0442:<\/p>\n<pre><code class=\"javascript\">class WorkersPool extends EventEmitter {   #queue;   #workers;   #portPool;    constructor({queue, workersPool}) {     super();      this.#queue = queue;     this.#workers = workersPool.length;     this.#portPool = [];      workersPool.forEach(worker => {       const channelS = new MessageChannel();       const channelD = new MessageChannel();       \/\/ \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u043a\u0430\u043d\u0430\u043b\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u0432 \u043f\u043e\u0442\u043e\u043a\u0443       worker.postMessage(         {           portS : channelS.port1         , portD : channelD.port1         }       , [ \/\/ \u043c\u0430\u0441\u0441\u0438\u0432 transferList - \u0431\u0435\u0437 \u044d\u0442\u043e\u0433\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0435 \u0431\u0443\u0434\u0435\u0442           channelS.port1         , channelD.port1         ]       );       \/\/ \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043a\u0430\u043d\u0430\u043b \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u043f\u0443\u043b       this.#portPool.push(channelD.port2);       \/\/ \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0441\u0438\u0433\u043d\u0430\u043b\u0430 \u043e\u0431 \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u0438 \u043f\u043e\u0442\u043e\u043a\u0430, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0435\u043c\u0443       channelS.port2.on('message', this.#onMessage.bind(this, channelD.port2));     });   }    #onMessage(port) {     \/\/ \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0435\u043c\u0443 \u043f\u043e\u0442\u043e\u043a\u0443 \u043e\u0442 1 \u0437\u0430\u043f\u0438\u0441\u0438 \u0434\u043e 1\/N \u0432\u0441\u0435\u0439 \u043e\u0447\u0435\u0440\u0435\u0434\u0438     const part = Math.ceil(this.#queue.length \/ this.#workers);     if (part) {       for (let i = 0; i &lt; part; i++) {         port.postMessage(this.#queue.shift());       }     }     else {       this.#portPool.push(port);     }   }    postMessage(msg) {     \/\/ \u0434\u043e\u0441\u0442\u0430\u0435\u043c \u0438\u0437 \u043f\u0443\u043b\u0430 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u044b\u0439 \u043a\u0430\u043d\u0430\u043b     const port = this.#portPool.pop();     if (port) {       port.postMessage(msg);     }     else {       \/\/ \u0435\u0441\u043b\u0438 \u0435\u0433\u043e \u043d\u0435\u0442 - \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u0438       this.#queue.push(msg);     }   } }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u043f\u043e\u0440\u0442\u0430 \u043e\u0431\u043c\u0435\u043d\u0430 \u0432 \u043f\u043e\u0442\u043e\u043a \u043c\u044b \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438\u0441\u044c \u0442\u0430\u043a\u043e\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439 \u043a\u0430\u043a <a href=\"https:\/\/nodejs.org\/dist\/latest-v16.x\/docs\/api\/worker_threads.html#portpostmessagevalue-transferlist\">transferList<\/a>. \u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044b\u0435 \u0432 \u043d\u0435\u043c <strong>\u043e\u0431\u044a\u0435\u043a\u0442\u044b \u043d\u0435 \u043a\u043e\u043f\u0438\u0440\u0443\u044e\u0442\u0441\u044f, \u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u044e\u0442\u0441\u044f<\/strong> \u043f\u043e\u0442\u043e\u043a\u0443 \u0432 \u0433\u043e\u0442\u043e\u0432\u043e\u043c \u0432\u0438\u0434\u0435 \u043a\u0430\u043a \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u044f\u0435\u043c\u043e\u0439 \u043f\u0430\u043c\u044f\u0442\u0438. \u0427\u0442\u043e\u0431\u044b \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u044b \u0434\u043e\u0441\u0442\u0443\u043f\u0430, \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u044e\u0449\u0435\u0433\u043e <strong>\u043e\u043d\u0438 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0440\u0430\u0437\u0440\u0443\u0448\u0430\u044e\u0442\u0441\u044f<\/strong> \u0438 \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u043d\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u044b.<\/p>\n<p>\u041e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0439 \u043a\u043e\u0434 \u043d\u0438\u043a\u0430\u043a \u043d\u0435 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f, \u0440\u0430\u0437\u0432\u0435 \u0447\u0442\u043e \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u0434\u043b\u044f \u043e\u0447\u0438\u0441\u0442\u043a\u0438 \u043f\u043e\u0434\u043f\u0438\u0441\u043e\u043a \u0442\u0435\u043f\u0435\u0440\u044c \u0437\u0432\u0430\u0442\u044c \u043d\u0435 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e.<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0442\u0435\u0441\u0442\u043e\u0432<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">const {   Worker , isMainThread , parentPort , MessageChannel       \/\/ \u043a\u0430\u043d\u0430\u043b \u043e\u0431\u043c\u0435\u043d\u0430 \u0441 \u043f\u043e\u0442\u043e\u043a\u043e\u043c , receiveMessageOnPort \/\/ \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043e\u0447\u0435\u0440\u0435\u0434\u0438 } = require('node:worker_threads');  const {   randomBytes , createHash } = require('node:crypto');  const hrtime = process.hrtime.bigint;  const EventEmitter = require('events'); class WorkersPool extends EventEmitter {   #queue;   #workers;   #portPool;    constructor({queue, workersPool}) {     super();      this.#queue = queue;     this.#workers = workersPool.length;     this.#portPool = [];      workersPool.forEach(worker => {       const channelS = new MessageChannel();       const channelD = new MessageChannel();       \/\/ \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u043a\u0430\u043d\u0430\u043b\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u0432 \u043f\u043e\u0442\u043e\u043a\u0443       worker.postMessage(         {           portS : channelS.port1         , portD : channelD.port1         }       , [ \/\/ transferList           channelS.port1         , channelD.port1         ]       );       \/\/ \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043a\u0430\u043d\u0430\u043b \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u043f\u0443\u043b       this.#portPool.push(channelD.port2);       \/\/ \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0441\u0438\u0433\u043d\u0430\u043b\u0430 \u043e\u0431 \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u0438 \u043f\u043e\u0442\u043e\u043a\u0430, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0435\u043c\u0443       channelS.port2.on('message', this.#onMessage.bind(this, channelD.port2));     });   }    #onMessage(port) {     \/\/ \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0435\u043c\u0443 \u043f\u043e\u0442\u043e\u043a\u0443 \u043e\u0442 1 \u0437\u0430\u043f\u0438\u0441\u0438 \u0434\u043e 1\/N \u0432\u0441\u0435\u0439 \u043e\u0447\u0435\u0440\u0435\u0434\u0438     const part = Math.ceil(this.#queue.length\/this.#workers);     if (part) {       for (let i = 0; i &lt; part; i++) {         port.postMessage(this.#queue.shift());       }     }     else {       this.#portPool.push(port);     }   }    postMessage(msg) {     \/\/ \u0434\u043e\u0441\u0442\u0430\u0435\u043c \u0438\u0437 \u043f\u0443\u043b\u0430 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u044b\u0439 \u043a\u0430\u043d\u0430\u043b     const port = this.#portPool.pop();     if (port) {       port.postMessage(msg);     }     else {       \/\/ \u0435\u0441\u043b\u0438 \u0435\u0433\u043e \u043d\u0435\u0442 - \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u0438       this.#queue.push(msg);     }   } }  if (isMainThread) {   const tsg = hrtime();   const messages = Array(1 &lt;&lt; 12).fill().map(_ => randomBytes(1 &lt;&lt; 16));   console.log('generated:', Number(hrtime() - tsg)\/1e6 | 0, 'ms');    const hashes = messages.map(() => undefined);   let remain;    const workers = [];   let active = 1;   let tsh;    let pool;   process     .on('test:start', () => {       hashes.fill();       remain = hashes.length;            const Pow2Buffer = require('.\/Pow2Buffer');       pool = new WorkersPool({         queue : new Pow2Buffer(8, 16)       , workersPool : workers.slice(0, active)       });        workers.forEach(worker => worker.eLU = worker.performance.eventLoopUtilization());       tsh = hrtime();       messages.forEach((data, id) => {         pool.postMessage({id, data});       });     })     .on('test:end', () => {       const duration = hrtime() - tsh;       workers.forEach(worker => worker.util = worker.performance.eventLoopUtilization(worker.eLU).utilization);       const avg = workers.slice(0, active).reduce((sum, worker) => sum + worker.util, 0)\/active;        console.log(         'hashed ' + active.toString().padStart(2) + ':'       , (Number(duration)\/1e6 | 0).toString().padStart(4)       , 'ms | ' + (avg * 100 | 0) + ' | '       , workers.map(           worker => (worker.util * 100 | 0).toString().padStart(2)         ).join(' ')       );        if (active &lt; n) {         active++;         process.emit('test:start');       }       else {         process.exit();       }     });    const n = 16;   Promise.all(     Array(n).fill().map(_ => {       return new Promise((resolve, reject) => {         const worker = new Worker(__filename);         worker           .on('online', () => resolve(worker))           .on('message', ({id, hash}) => {             hashes[id] = hash;             if (!--remain) {               process.emit('test:end');             }           });       });         })   )     .then((result) => {       workers.push(...result);       process.emit('test:start');     }); } else {   \/\/ \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0430\u0442\u043e\u043c\u0430\u0440\u043d\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f   const processMessage = ({id, data}) => parentPort.postMessage({id, hash : createHash('sha256').update(data).digest('hex')});   \/\/ \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u043e\u0439 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043f\u043e\u0440\u0442\u043e\u0432   parentPort.on('message', ({portS, portD}) => {     portD.on('message', message => {       \/\/ \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u043d\u043e\u0432\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445       processMessage(message);       \/\/ ... \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c \u0432\u0441\u044e \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u043a\u0430\u043d\u0430\u043b\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043e \u043a\u043e\u043d\u0446\u0430       do {         const recv = receiveMessageOnPort(portD);         if (!recv) {           break;         }         processMessage(recv.message);       }       while (true);       \/\/ \u0432\u0441\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 - \u0441\u043e\u043e\u0431\u0449\u0430\u0435\u043c \u0432 \u0441\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u0430\u043d\u0430\u043b, \u0447\u0442\u043e \u043f\u043e\u0442\u043e\u043a \u0441\u0432\u043e\u0431\u043e\u0434\u0435\u043d       portS.postMessage(undefined);     });   }); }<\/code><\/pre>\n<pre><code>generated: 278 ms hashed  1: 1120 ms | 99 |  99  0  0  0  0  0  0  0  0  0  0  0  0  0  1  0 hashed  2:  596 ms | 93 |  99 87  0  0  0  0  0  0  0  0  0  0  0  0  0  0 hashed  3:  452 ms | 90 |  99 89 82  0  0  0  0  0  0  0  0  0  0  0  0  0 hashed  4:  403 ms | 85 |  80 87 98 75  0  0  0  0  0  0  0  0  0  0  0  0 hashed  5:  483 ms | 57 |  47 86 59 49 43  0  0  0  0  0  0  0  0  0  0  0 hashed  6:  427 ms | 62 |  44 46 63 92 73 56  0  0  0  0  0  0  0  0  0  0 hashed  7:  334 ms | 74 |  67 68 76 78 90 84 54  0  0  0  0  0  0  0  0  0 hashed  8:  519 ms | 36 |  17 16 41 14 41 50 95 15  0  0  0  0  0  0  0  0 hashed  9:  332 ms | 70 |  51 45 65 67 88 79 79 88 65  0  0  0  0  0  0  0 hashed 10:  448 ms | 41 |  17 35 49 34 35 37 96 52 32 26  0  0  0  0  0  0 hashed 11:  317 ms | 70 |  42 59 63 76 54 79 67 89 69 87 82  0  0  0  0  0 hashed 12:  314 ms | 71 |  53 55 84 53 63 91 60 82 80 84 82 65  0  0  0  0 hashed 13:  350 ms | 52 |  42 39 41 55 30 47 66 50 70 72 67 57 42  0  0  0 hashed 14:  325 ms | 64 |  46 47 45 59 27 76 67 66 60 82 76 88 84 73  0  0 hashed 15:  316 ms | 51 |  27 65 31 28 64 18 51 53 68 76 58 67 74 49 41  0 hashed 16:  321 ms | 48 |  17 77 32 41 21 41 25 76 82 45 39 58 54 83 44 40<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/5a8\/2bb\/477\/5a82bb477db8a1c318a659bf3dbcd9fe.png\" alt=\"MessageChannel \u043f\u0440\u043e\u0442\u0438\u0432 \u0432\u0441\u0435\u0445\" title=\"MessageChannel \u043f\u0440\u043e\u0442\u0438\u0432 \u0432\u0441\u0435\u0445\" width=\"1202\" height=\"471\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5a8\/2bb\/477\/5a82bb477db8a1c318a659bf3dbcd9fe.png\"\/><figcaption>MessageChannel \u043f\u0440\u043e\u0442\u0438\u0432 \u0432\u0441\u0435\u0445<\/figcaption><\/figure>\n<p>\u041d\u0430 \u043c\u0430\u043b\u043e\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u043f\u043e\u0447\u0442\u0438 \u0432\u044b\u0448\u043b\u0438 \u043d\u0430 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u0438 Round-robin, \u0430 \u0432\u043e\u0442 \u043d\u0430 \u0431\u043e\u043b\u044c\u0448\u043e\u043c \u0438\u043d\u043e\u0433\u0434\u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e &#171;\u0448\u0442\u043e\u0440\u043c\u0438\u0442&#187; \u043e\u0442 \u043d\u0435\u0440\u0430\u0432\u043d\u043e\u043c\u0435\u0440\u043d\u043e\u0441\u0442\u0438 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043e\u0447\u0435\u0440\u0435\u0434\u0438. \u0412 \u043e\u0431\u0449\u0435\u043c, \u043d\u0435 \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u0438\u0437\u043d\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0439 \u043e\u043f\u044b\u0442 \u043e\u0434\u043d\u043e\u0437\u043d\u0430\u0447\u043d\u043e \u043f\u043e\u043b\u043e\u0436\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c.<\/p>\n<h2>\u041f\u043e\u0442\u043e\u043a-\u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440<\/h2>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u043e\u0431\u0430 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u043c\u0435\u0442\u043e\u0434\u0430.<\/p>\n<p>\u0412 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u043e\u0447\u0435\u0440\u0435\u0434\u044c\u044e \u043d\u0430\u0441 \u043d\u0435 \u0443\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u043b\u0438 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0433\u043e\u0442\u043e\u0432\u043d\u043e\u0441\u0442\u0438 \u0437\u0430\u0434\u0430\u0447 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 &#8212; \u0442\u0430\u043a \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0435\u0435 \u0432\u043e\u043e\u0431\u0449\u0435 \u0432\u044b\u043d\u0435\u0441\u0435\u043c \u0432 \u0434\u0440\u0443\u0433\u043e\u0439, \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439, \u043f\u043e\u0442\u043e\u043a &#8212;<strong> \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u0430\u043c \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0438<\/strong> \u043c\u0435\u0436\u0434\u0443 \u0440\u0430\u0431\u043e\u0447\u0438\u043c\u0438 \u043f\u043e\u0442\u043e\u043a\u0430\u043c\u0438.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/5cd\/e3e\/d89\/5cde3ed899e13c02103f736028935360.png\" alt=\"\u0421\u0445\u0435\u043c\u0430 \u0443\u0432\u044f\u0437\u043a\u0438 \u0440\u0430\u0431\u043e\u0447\u0438\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u0438 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440\u0430\" title=\"\u0421\u0445\u0435\u043c\u0430 \u0443\u0432\u044f\u0437\u043a\u0438 \u0440\u0430\u0431\u043e\u0447\u0438\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u0438 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440\u0430\" width=\"643\" height=\"265\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5cd\/e3e\/d89\/5cde3ed899e13c02103f736028935360.png\"\/><figcaption>\u0421\u0445\u0435\u043c\u0430 \u0443\u0432\u044f\u0437\u043a\u0438 \u0440\u0430\u0431\u043e\u0447\u0438\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u0438 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440\u0430<\/figcaption><\/figure>\n<p>\u0412 \u043a\u043e\u0434\u0435 \u043c\u044b \u0441\u0440\u0430\u0437\u0443 \u0447\u0435\u0440\u0435\u0437 <code>workerData<\/code> \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c <strong>\u0441\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u0430\u043d\u0430\u043b \u0438 \u0442\u0438\u043f \u043f\u043e\u0442\u043e\u043a\u0430<\/strong>. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0434 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0440\u0430\u0431\u043e\u0447\u0438\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432:<\/p>\n<pre><code class=\"javascript\">  const n = 16;   Promise.all(     Array(n).fill().map(_ => new Promise((resolve, reject) => {       \/\/ \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u043e\u0442\u043e\u043a \u0438 \u0441\u043b\u0443\u0436\u0435\u0431\u043d\u044b\u0439 \u043a\u0430\u043d\u0430\u043b \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441 \u043d\u0438\u043c       const channel = new MessageChannel();       const worker = new Worker(__filename,         {           workerData   : {             signalPort : channel.port1           , workerType : 'worker'           }         , transferList : [channel.port1]         }       );       worker.signalPort = channel.port2;       worker         .on('online', () => resolve(worker))         .on('message', ({id, hash}) => {           hashes[id] = hash;           if (!--remain) {             process.emit('test:end');           }         });     }))   ) \/\/ ...<\/code><\/pre>\n<p> \u0410 \u043f\u043e\u0442\u043e\u043c \u0443\u0436\u0435 \u0447\u0435\u0440\u0435\u0437 \u044d\u0442\u043e\u0442 \u0441\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u0430\u043d\u0430\u043b \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u043f\u043e\u0440\u0442 \u043e\u0431\u043c\u0435\u043d\u0430 \u043c\u0435\u0436\u0434\u0443 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440\u043e\u043c \u0438 worker&#8217;\u043e\u043c:<\/p>\n<pre><code class=\"javascript\">\/\/ ...   process     .on('test:start', () => {       \/\/ ...       \/\/ \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u043f\u043e\u0442\u043e\u043a-\u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440 \u0438 \u0441\u043b\u0443\u0436\u0435\u0431\u043d\u044b\u0439 \u043a\u0430\u043d\u0430\u043b \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441 \u043d\u0438\u043c       const channel = new MessageChannel();       const coordinator = new Worker(__filename,         {           workerData   : {             signalPort : channel.port1           , workerType : 'coordinator'           }         , transferList : [channel.port1]         }       );       coordinator.signalPort = channel.port2;       coordinator.signalPort.setMaxListeners(0);        coordinator.on('online', () => {         Promise.all(           workers.slice(0, active)             \/\/ \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u043a\u0430\u043d\u0430\u043b \u043e\u0431\u043c\u0435\u043d\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439             \/\/ \u043e\u0434\u0438\u043d \u043f\u043e\u0440\u0442 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u043c\u0443 \u043f\u043e\u0442\u043e\u043a\u0443, \u0432\u0442\u043e\u0440\u043e\u0439 - \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440\u0443             .flatMap(worker => {               const {port1, port2} = new MessageChannel();               return [{worker, port : port1}, {worker : coordinator, port : port2}];             })             .map(adressee => new Promise((resolve, reject) => {               const {worker, port} = adressee;               worker.signalPort.once('message', () => resolve(adressee));               worker.signalPort.postMessage(port, [port]);             }))         )           .then(ports => {             \/\/ \u0437\u0430\u043f\u0443\u0441\u043a \u0442\u0435\u0441\u0442\u0430             workers.forEach(worker => worker.eLU = worker.performance.eventLoopUtilization());             tsh = hrtime();             messages.forEach((data, id) => {               coordinator.postMessage({id, data}); \/\/ \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0432\u0441\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440\u0443             });           });       }); \/\/ ...<\/code><\/pre>\n<p>\u0410 \u0432\u043e\u0442 \u043a\u043e\u0434 \u0441\u0430\u043c\u0438\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u043f\u043e\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u0441\u0438\u043b\u044c\u043d\u0435\u0435. \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044e <code>switch-case<\/code> &#8212; \u0432 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c \u0435\u0435 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0447\u0430\u0441\u0442\u043e \u043a\u0430\u043a \u0434\u043b\u044f \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043b\u043e\u0433\u0438\u043a\u0438 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0442\u0438\u043f\u043e\u0432 \u043f\u043e\u0442\u043e\u043a\u043e\u0432, \u0442\u0430\u043a \u0438 \u043f\u0440\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0440\u0430\u0437\u043d\u044b\u0445 \u0442\u0438\u043f\u043e\u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439:<\/p>\n<pre><code class=\"javascript\">\/\/ ... else {   const {signalPort, workerType} = workerData;   switch (workerType) {     case 'worker':       const processMessage = ({id, data}) => parentPort.postMessage({id, hash : createHash('sha256').update(data).digest('hex')});       \/\/ \u043f\u043e \u0441\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u043e\u043c\u0443 \u043a\u0430\u043d\u0430\u043b\u0443 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u043f\u043e\u0440\u0442 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440\u0430       signalPort.on('message', port => {         port.on('message', message => {           processMessage(message);           port.postMessage(undefined); \/\/ \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c 'ready for task'         });         signalPort.postMessage(undefined); \/\/ \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c 'online'       });       break;     case 'coordinator':       const pool = [];       const queue = new (require('.\/Pow2Buffer'))(8, 16);       \/\/ \u043f\u043e \u0441\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u043e\u043c\u0443 \u043a\u0430\u043d\u0430\u043b\u0443 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u043f\u043e\u0440\u0442 worker'\u0430       signalPort.on('message', port => {         \/\/ \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u043f\u0443\u043b \u0438 \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c\u0441\u044f \u043d\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0441\u0438\u0433\u043d\u0430\u043b\u0430 \u0433\u043e\u0442\u043e\u0432\u043d\u043e\u0441\u0442\u0438 \u043e\u0442 worker'\u0430         pool.push(port);         port.on('message', () => {           const message = queue.shift();           if (message) {             port.postMessage(message);           }           else {             pool.push(port);           }         });         signalPort.postMessage(undefined);       });       \/\/ \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0432\u0445\u043e\u0434\u044f\u0449\u0435\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440\u0443       parentPort.on('message', message => {         const port = pool.pop();         if (port) {           port.postMessage(message);         }         else {           queue.push(message);         }       });       break;   } }<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0443\u0435\u043c \u0432\u0441\u0435 \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0438, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u0434\u0430\u0447\u0430, \u043f\u043e\u043f\u0430\u0432\u0448\u0430\u044f \u0432 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440, \u0431\u044b\u043b\u0430 \u0432\u044b\u0434\u0430\u043d\u0430 \u043f\u0435\u0440\u0432\u043e\u043c\u0443 \u0436\u0435 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u043c\u0443 (\u0438\u043b\u0438 \u043e\u0441\u0432\u043e\u0431\u043e\u0434\u0438\u0432\u0448\u0435\u043c\u0443\u0441\u044f) \u043f\u043e\u0442\u043e\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0442\u043e\u043c \u0441\u0430\u043c \u0441\u043a\u0438\u043d\u0435\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432 <code>parentPort<\/code> \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c\u0443 \u043f\u043e\u0442\u043e\u043a\u0443, \u0441\u043e\u043e\u0431\u0449\u0438\u0432 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440\u0443 \u043e \u0441\u0432\u043e\u0435\u0439 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u0438:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b9b\/ef3\/b44\/b9bef3b441b99d41c984a2770e8de40f.png\" alt=\"\u0421\u0445\u0435\u043c\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0437\u0430\u0434\u0430\u0447\u0438 \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440\" title=\"\u0421\u0445\u0435\u043c\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0437\u0430\u0434\u0430\u0447\u0438 \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440\" width=\"473\" height=\"606\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b9b\/ef3\/b44\/b9bef3b441b99d41c984a2770e8de40f.png\"\/><figcaption>\u0421\u0445\u0435\u043c\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0437\u0430\u0434\u0430\u0447\u0438 \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440<\/figcaption><\/figure>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0442\u0435\u0441\u0442\u043e\u0432<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">const {   Worker , isMainThread , parentPort , workerData , MessageChannel } = require('node:worker_threads');  const {   randomBytes , createHash } = require('node:crypto');  const hrtime = process.hrtime.bigint;  if (isMainThread) {   const tsg = hrtime();   const messages = Array(1 &lt;&lt; 12).fill().map(_ => randomBytes(1 &lt;&lt; 16));   console.log('generated:', Number(hrtime() - tsg)\/1e6 | 0, 'ms');    const hashes = messages.map(() => undefined);   let remain;    const workers = [];   let active = 1;   let tsh;    process     .on('test:start', () => {       hashes.fill();       remain = hashes.length;        \/\/ \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u043f\u043e\u0442\u043e\u043a-\u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440 \u0438 \u0441\u043b\u0443\u0436\u0435\u0431\u043d\u044b\u0439 \u043a\u0430\u043d\u0430\u043b \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441 \u043d\u0438\u043c       const channel = new MessageChannel();       const coordinator = new Worker(__filename,         {           workerData   : {             signalPort : channel.port1           , workerType : 'coordinator'           }         , transferList : [channel.port1]         }       );       coordinator.signalPort = channel.port2;       coordinator.signalPort.setMaxListeners(0);        coordinator.on('online', () => {         Promise.all(           workers.slice(0, active)             \/\/ \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u043a\u0430\u043d\u0430\u043b \u043e\u0431\u043c\u0435\u043d\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439             \/\/ \u043e\u0434\u0438\u043d \u043f\u043e\u0440\u0442 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u043c\u0443 \u043f\u043e\u0442\u043e\u043a\u0443, \u0432\u0442\u043e\u0440\u043e\u0439 - \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440\u0443             .flatMap(worker => {               const {port1, port2} = new MessageChannel();               return [{worker, port : port1}, {worker : coordinator, port : port2}];             })             .map(adressee => new Promise((resolve, reject) => {               const {worker, port} = adressee;               worker.signalPort.once('message', () => resolve(adressee));               worker.signalPort.postMessage(port, [port]);             }))         )           .then(ports => {             \/\/ \u0437\u0430\u043f\u0443\u0441\u043a \u0442\u0435\u0441\u0442\u0430             workers.forEach(worker => worker.eLU = worker.performance.eventLoopUtilization());             tsh = hrtime();             messages.forEach((data, id) => {               coordinator.postMessage({id, data}); \/\/ \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0432\u0441\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440\u0443             });           });       });     })     .on('test:end', () => {       const duration = hrtime() - tsh;       workers.forEach(worker => worker.util = worker.performance.eventLoopUtilization(worker.eLU).utilization);       const avg = workers.slice(0, active).reduce((sum, worker) => sum + worker.util, 0)\/active;        console.log(         'hashed ' + active.toString().padStart(2) + ':'       , (Number(duration)\/1e6 | 0).toString().padStart(4)       , 'ms | ' + (avg * 100 | 0) + ' | '       , workers.map(           worker => (worker.util * 100 | 0).toString().padStart(2)         ).join(' ')       );        if (active &lt; n) {         active++;         process.emit('test:start');       }       else {         process.exit();       }     });    const n = 16;   Promise.all(     Array(n).fill().map(_ => new Promise((resolve, reject) => {       \/\/ \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u043e\u0442\u043e\u043a \u0438 \u0441\u043b\u0443\u0436\u0435\u0431\u043d\u044b\u0439 \u043a\u0430\u043d\u0430\u043b \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441 \u043d\u0438\u043c       const channel = new MessageChannel();       const worker = new Worker(__filename,         {           workerData   : {             signalPort : channel.port1           , workerType : 'worker'           }         , transferList : [channel.port1]         }       );       worker.signalPort = channel.port2;       worker         .on('online', () => resolve(worker))         .on('message', ({id, hash}) => {           hashes[id] = hash;           if (!--remain) {             process.emit('test:end');           }         });     }))   )     .then(result => {       workers.push(...result);       process.emit('test:start');     }); } else {   const {signalPort, workerType} = workerData;   switch (workerType) {     case 'worker':       const processMessage = ({id, data}) => parentPort.postMessage({id, hash : createHash('sha256').update(data).digest('hex')});       \/\/ \u043f\u043e \u0441\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u043e\u043c\u0443 \u043a\u0430\u043d\u0430\u043b\u0443 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u043f\u043e\u0440\u0442 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440\u0430       signalPort.on('message', port => {         port.on('message', message => {           processMessage(message);           port.postMessage(undefined); \/\/ \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c 'ready for task'         });         signalPort.postMessage(undefined); \/\/ \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c 'online'       });       break;     case 'coordinator':       const pool = [];       const queue = new (require('.\/Pow2Buffer'))(8, 16);       \/\/ \u043f\u043e \u0441\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u043e\u043c\u0443 \u043a\u0430\u043d\u0430\u043b\u0443 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u043f\u043e\u0440\u0442 worker'\u0430       signalPort.on('message', port => {         \/\/ \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u043f\u0443\u043b \u0438 \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c\u0441\u044f \u043d\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0441\u0438\u0433\u043d\u0430\u043b\u0430 \u0433\u043e\u0442\u043e\u0432\u043d\u043e\u0441\u0442\u0438 \u043e\u0442 worker'\u0430         pool.push(port);         port.on('message', () => {           const message = queue.shift();           if (message) {             port.postMessage(message);           }           else {             pool.push(port);           }         });         signalPort.postMessage(undefined);       });       \/\/ \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0432\u0445\u043e\u0434\u044f\u0449\u0435\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440\u0443       parentPort.on('message', message => {         const port = pool.pop();         if (port) {           port.postMessage(message);         }         else {           queue.push(message);         }       });       break;   } }<\/code><\/pre>\n<pre><code>generated: 281 ms hashed  1: 1396 ms | 81 |  81  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 hashed  2:  804 ms | 75 |  74 76  0  0  0  0  0  0  0  0  0  0  0  0  0  0 hashed  3:  604 ms | 66 |  65 67 67  0  0  0  0  0  0  0  0  0  0  0  0  0 hashed  4:  478 ms | 62 |  62 61 63 63  0  0  0  0  0  0  0  0  0  0  0  0 hashed  5:  483 ms | 51 |  50 50 48 54 52  0  0  0  0  0  0  0  0  0  0  0 hashed  6:  495 ms | 49 |  48 51 45 50 49 48  0  0  0  0  0  0  0  0  0  0 hashed  7:  500 ms | 40 |  40 39 40 43 37 41 41  0  0  0  0  0  0  0  0  0 hashed  8:  549 ms | 32 |  33 33 33 23 24 42 32 34  0  0  0  0  0  0  0  0 hashed  9:  602 ms | 28 |  21 35 25 27 35 20 26 30 30  0  0  0  0  0  0  0 hashed 10:  518 ms | 27 |  22 29 17 32 28 24 33 35 33 22  0  0  0  0  0  0 hashed 11:  522 ms | 28 |  27 22 24 26 34 29 39 33 29 21 24  0  0  0  0  0 hashed 12:  543 ms | 25 |  31 19 19 25 24 31 30 27 25 28 16 22  0  1  1  0 hashed 13:  541 ms | 23 |  21 20 19 24 20 28 32 21 27 28 21 17 21  1  2  1 hashed 14:  549 ms | 22 |  17 22 21 20 25 19 18 25 26 29 25 21 23 20  0  0 hashed 15:  557 ms | 23 |  31 33 32 27 17 25 20 20 21 23 20 17 23 18 19  0 hashed 16:  570 ms | 22 |  24 23 19 21 19 29 23 21 21 13 26 22 21 24 24 26<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f24\/cb5\/85e\/f24cb585e2be87b2b8e0ab79f332a147.png\" alt=\"\u041e\u0447\u0435\u0440\u0435\u0434\u044c \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435-\u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440\u0435\" title=\"\u041e\u0447\u0435\u0440\u0435\u0434\u044c \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435-\u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440\u0435\" width=\"1202\" height=\"471\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f24\/cb5\/85e\/f24cb585e2be87b2b8e0ab79f332a147.png\"\/><figcaption>\u041e\u0447\u0435\u0440\u0435\u0434\u044c \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435-\u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440\u0435<\/figcaption><\/figure>\n<p>\u0418&#8230; \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0445\u043e\u0442\u044c \u0438 \u0440\u0430\u0434\u0443\u044e\u0442 \u0440\u0430\u0432\u043d\u043e\u043c\u0435\u0440\u043d\u043e\u0441\u0442\u044c\u044e \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043c\u0435\u0436\u0434\u0443 \u043f\u043e\u0442\u043e\u043a\u0430\u043c\u0438, \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u0432\u043f\u0435\u0447\u0430\u0442\u043b\u044f\u044e\u0442 \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u043e\u0431\u0449\u0435\u0439 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p>\u0422\u043e \u0435\u0441\u0442\u044c \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0432\u043f\u043e\u043b\u043d\u0435 \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c, \u0435\u0441\u043b\u0438 \u0441\u0430\u043c\u043e <strong>\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u0434\u043b\u044f \u043f\u043e\u0442\u043e\u043a\u0430 \u0438\u043b\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0435\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e-\u0441\u043b\u043e\u0436\u043d\u044b\u043c\u0438<\/strong> &#8212; \u0442\u043e\u0433\u0434\u0430 \u0438\u0445 \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b \u0432\u044b\u043d\u043e\u0441\u0438\u0442\u044c \u0432 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440. \u041d\u043e \u0432 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0435 \u0442\u0438\u043f\u043e\u0432\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u0435\u0432 \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0441\u0435\u0431\u044f \u043d\u0435 \u043b\u0443\u0447\u0448\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c.<\/p>\n<p>\u0410 \u0432\u0441\u0435 \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e, \u0441 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b, \u043c\u044b \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u043a\u043e\u043d\u0442\u0435\u043d\u0442 \u0437\u0430\u0434\u0430\u0447\u0438 \u0438\u0437 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 \u0432 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440, \u043f\u043e\u0442\u043e\u043c \u0438\u0437 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440\u0430 \u0432 \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u043f\u043e\u0442\u043e\u043a, \u0430 \u0441 \u0434\u0440\u0443\u0433\u043e\u0439 &#8212; worker \u0431\u0435\u0441\u0446\u0435\u043b\u044c\u043d\u043e \u0436\u0434\u0435\u0442, \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u043e\u0442\u0440\u0435\u0430\u0433\u0438\u0440\u0443\u0435\u043c \u043d\u0430 \u0435\u0433\u043e \u0433\u043e\u0442\u043e\u0432\u043d\u043e\u0441\u0442\u044c. \u0418 \u0447\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u0443\u0447\u0430\u0441\u0442\u0432\u0443\u0435\u0442 \u0432 \u0442\u0430\u043a\u043e\u0439 \u0441\u0445\u0435\u043c\u0435, \u0442\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0434\u043e\u043b\u044e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043e\u043d\u0438 \u0432\u044b\u043d\u0443\u0436\u0434\u0435\u043d\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0430\u0438\u0432\u0430\u044e\u0442.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/0bf\/b3f\/399\/0bfb3f399a0952749836f5bcd4bcf8d3.png\" alt=\"\u041e\u0436\u0438\u0434\u0430\u043d\u0438\u0435 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u0432 \u0441\u0445\u0435\u043c\u0435 \u0441 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440\u043e\u043c\" title=\"\u041e\u0436\u0438\u0434\u0430\u043d\u0438\u0435 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u0432 \u0441\u0445\u0435\u043c\u0435 \u0441 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440\u043e\u043c\" width=\"908\" height=\"379\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/0bf\/b3f\/399\/0bfb3f399a0952749836f5bcd4bcf8d3.png\"\/><figcaption>\u041e\u0436\u0438\u0434\u0430\u043d\u0438\u0435 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u0432 \u0441\u0445\u0435\u043c\u0435 \u0441 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440\u043e\u043c<\/figcaption><\/figure>\n<p>\u0410 \u043d\u0435\u043b\u044c\u0437\u044f \u043b\u0438 \u043a\u0430\u043a-\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0442\u043e\u043a\u0438 \u0437\u0430\u0431\u0438\u0440\u0430\u043b\u0438 \u0438 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u043b\u0438 \u0437\u0430\u0434\u0430\u0447\u0438 \u043c\u0435\u0436\u0434\u0443 \u0441\u043e\u0431\u043e\u0439 &#171;\u0441\u0430\u043c\u0438&#187;, \u043d\u0435 \u043e\u0436\u0438\u0434\u0430\u044f \u0431\u0435\u0441\u0446\u0435\u043b\u044c\u043d\u043e, \u043f\u043e\u043a\u0430 \u0438\u043c \u043a\u0442\u043e-\u0442\u043e \u044d\u0442\u043e \u0441\u043a\u043e\u043c\u0430\u043d\u0434\u0443\u0435\u0442? \u041e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f, \u043c\u043e\u0436\u043d\u043e, \u043d\u043e \u043f\u0440\u043e \u044d\u0442\u043e &#8212; \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0447\u0430\u0441\u0442\u0438.<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"v-portal\" style=\"display:none;\"><\/div>\n<\/div>\n<p> <!----> <!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/company\/tensor\/blog\/689406\/\"> https:\/\/habr.com\/ru\/company\/tensor\/blog\/689406\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><figcaption>Multithreading \u043a\u0430\u043a \u043e\u043d \u0435\u0441\u0442\u044c<\/figcaption><\/figure>\n<p>\u0412 <a href=\"\/ru\/post\/689144\/\">\u043f\u0435\u0440\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0441\u0442\u0430\u0442\u044c\u0438<\/a> \u043c\u044b \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438\u0441\u044c \u043d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442\u0435, \u043a\u043e\u0433\u0434\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447 \u043c\u0435\u0436\u0434\u0443 \u043f\u043e\u0442\u043e\u043a\u0430\u043c\u0438 \u043f\u043e \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0443 <a href=\"https:\/\/ru.wikipedia.org\/wiki\/Round-robin_(%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC)\">Round-robin<\/a> \u043c\u044b \u0434\u043e\u0431\u0438\u043b\u0438\u0441\u044c-\u0442\u0430\u043a\u0438 \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0437\u0430 \u0441\u0447\u0435\u0442 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p>\u041d\u043e \u0432\u043e\u0442 \u043d\u0435\u043f\u0440\u0438\u044f\u0442\u043d\u043e\u0441\u0442\u044c: \u0442\u0430\u043a\u043e\u0439 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u043e\u0447\u0435\u043d\u044c <strong>\u043d\u0435\u0440\u0430\u0432\u043d\u043e\u043c\u0435\u0440\u043d\u043e \u043d\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u043f\u043e\u0442\u043e\u043a\u0438<\/strong> <strong>\u0438 \u043d\u0435 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0443\u0442\u0438\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442 \u0438\u0445<\/strong> \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 &#8212; \u043f\u043e\u043a\u0430 \u043a\u0442\u043e-\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u0430\u0438\u0432\u0430\u0435\u0442, \u0434\u0440\u0443\u0433\u043e\u0439 \u0443\u0436\u0435 \u043a\u043e\u043f\u0438\u0442 \u043e\u0447\u0435\u0440\u0435\u0434\u044c. \u041a\u0430\u043a \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u043e\u0431\u043e\u0439\u0442\u0438?<\/p>\n<h3>\u041f\u0443\u043b \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u0438 \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0437\u0430\u0434\u0430\u0447<\/h3>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0432\u043c\u0435\u0441\u0442\u043e &#171;\u0437\u0430\u043f\u0438\u0445\u0438\u0432\u0430\u043d\u0438\u044f&#187; \u0437\u0430\u0434\u0430\u0447\u0438 \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c <strong>\u043e\u0431\u0449\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c<\/strong> \u0434\u043b\u044f \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e <strong>\u043f\u0443\u043b\u0430 \u043f\u043e\u0442\u043e\u043a\u043e\u0432<\/strong>:<\/p>\n<ul>\n<li>\n<p>\u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0437\u0430\u0434\u0430\u0447\u0438 \u043e\u0442\u0434\u0430\u0435\u043c \u0435\u0435 \u043f\u0435\u0440\u0432\u043e\u043c\u0443 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u043c\u0443 \u043f\u043e\u0442\u043e\u043a\u0443 \u0438\u043b\u0438 \u0441\u0442\u0430\u0432\u0438\u043c \u0432 \u043e\u0431\u0449\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u043a\u043e\u0433\u0434\u0430 \u0442\u0430\u043a\u0438\u0445 \u043d\u0435\u0442;<\/p>\n<\/li>\n<li>\n<p>\u043f\u0440\u0438 \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u0438 \u043f\u043e\u0442\u043e\u043a\u0430 \u0441\u0440\u0430\u0437\u0443 \u0434\u0430\u0435\u043c \u0435\u043c\u0443 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443 \u0438\u0437 \u043e\u0447\u0435\u0440\u0435\u0434\u0438.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0442\u0430\u043a\u043e\u0439 \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438 \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u043c\u0430\u0441\u0441\u0438\u0432. \u041d\u043e \u043b\u0443\u0447\u0448\u0435 \u043d\u0435 \u0441\u0442\u043e\u0438\u0442 \u0438\u0437-\u0437\u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 <code>Array.shift()<\/code>, \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0445 \u0432 <a href=\"\/ru\/post\/688182\/\">\u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435<\/a> &#8212; \u0442\u0430\u043a \u0447\u0442\u043e \u0432\u043e\u0437\u044c\u043c\u0435\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043a\u043e\u043b\u044c\u0446\u0435\u0432\u043e\u0433\u043e \u0431\u0443\u0444\u0435\u0440\u0430, \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u043d\u0443\u044e \u0442\u0430\u043c \u0436\u0435.<\/p>\n<figure class=\"full-width\"><figcaption>\u0421\u0445\u0435\u043c\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043e\u0431\u0449\u0435\u0439 \u043e\u0447\u0435\u0440\u0435\u0434\u044c\u044e<\/figcaption><\/figure>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u043e\u0442\u043b\u0438\u0447\u0438\u0435\u043c \u043e\u0442 \u0441\u0445\u0435\u043c\u044b \u0441 Round-robin, \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u043d\u043e\u0439 \u0432 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0447\u0430\u0441\u0442\u0438, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u043f\u0430\u0434\u0430\u043d\u0438\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u0432 \u043f\u043e\u0442\u043e\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u0433\u0434\u0430 \u043e\u043d \u0443\u0436\u0435 \u0433\u043e\u0442\u043e\u0432 \u0435\u0439 \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c\u0441\u044f, \u043f\u0440\u0438\u0447\u0435\u043c \u0441\u0440\u0430\u0437\u0443 \u043f\u0440\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439.<\/p>\n<p>\u041c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0432 \u043d\u0430\u0448\u0435\u043c \u043a\u043e\u0434\u0435 \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043d\u0435\u0432\u0435\u043b\u0438\u043a\u0438 &#8212; \u0441\u0430\u043c\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043b\u0430\u0441\u0441\u0430 <code>WorkersPool<\/code>:<\/p>\n<pre><code class=\"javascript\">\/\/ ... const EventEmitter = require('events'); class WorkersPool extends EventEmitter {   #queue;   #workersPool;   #currentWorker;   #onMessageHandler = Symbol('handler');    constructor({queue, workersPool}) {     super();      this.#queue = queue;     this.#workersPool = [...workersPool];      \/\/ \u043d\u0430\u0432\u0435\u0448\u0438\u0432\u0430\u0435\u043c \u0441\u0432\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432 \u0441\u0430\u043c\u043e\u0435 \u043d\u0430\u0447\u0430\u043b\u043e \u0446\u0435\u043f\u043e\u0447\u043a\u0438     this.#workersPool.forEach(worker => {       worker[this.#onMessageHandler] = this.#onMessage.bind(this, worker);       worker.prependListener('message', worker[this.#onMessageHandler]);     });   }    destructor() {     \/\/  \u0433\u0430\u0441\u0438\u043c \u0441\u0432\u043e\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438     this.#workersPool.forEach(worker => {       worker.off('message', worker[this.#onMessageHandler]);       delete worker[this.#onMessageHandler];     });   }    #onMessage(worker) {     \/\/ \u0435\u0441\u043b\u0438 \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u0447\u0442\u043e-\u0442\u043e \u0435\u0441\u0442\u044c - \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0432\u044b\u0437\u0432\u0430\u0432\u0448\u0435\u043c\u0443     const msg = this.#queue.shift();     if (msg) {       worker.postMessage(msg);     }     \/\/ \u0435\u0441\u043b\u0438 \u043d\u0435\u0442 - \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0435\u0433\u043e \u0436\u0434\u0430\u0442\u044c \u0432 \u043f\u0443\u043b\u0435     else {       this.#workersPool.push(worker);     }   }    postMessage(msg) {     \/\/ \u0434\u043e\u0441\u0442\u0430\u0435\u043c \u0438\u0437 \u043f\u0443\u043b\u0430 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u044b\u0439 \u0432\u043e\u0440\u043a\u0435\u0440     const worker = this.#workersPool.pop();     if (worker) {       worker.postMessage(msg);     }     else {       \/\/ \u0435\u0441\u043b\u0438 \u0435\u0433\u043e \u043d\u0435\u0442 - \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u0438       this.#queue.push(msg);     }   } } \/\/ ...<\/code><\/pre>\n<p>&#8230; \u0438 \u043f\u0430\u0440\u0430 \u043c\u0435\u0441\u0442 \u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f:<\/p>\n<pre><code class=\"javascript\">\/\/ ... if (isMainThread) {   \/\/ ...   let pool; \/\/ \u044d\u0442\u043e \u043d\u0430\u0448 \u043f\u0443\u043b   process     .on('test:start', () => {       \/\/ ...       \/\/ \u043f\u0443\u043b \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u0441 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u043e\u0447\u0435\u0440\u0435\u0434\u044c\u044e       const Pow2Buffer = require('.\/Pow2Buffer');       pool = new WorkersPool({         queue : new Pow2Buffer(8, 16)       , workersPool : workers.slice(0, active)       });       \/\/ ...       messages.forEach((data, id) => {         pool.postMessage({id, data}); \/\/ \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0432\u0441\u0435 \u0432 \u043f\u0443\u043b       });     })     .on('test:end', () => {       \/\/ ...       if (active &lt; n) {         pool.destructor(); \/\/ \u0437\u0430\u0447\u0438\u0449\u0430\u0435\u043c \u043f\u043e\u0442\u043e\u043a\u0438 \u043f\u0443\u043b\u0430 \u043e\u0442 \u043d\u0430\u0448\u0438\u0445 \u043f\u043e\u0434\u043f\u0438\u0441\u043e\u043a         active++;         process.emit('test:start');       }       else {         process.exit();       }     }); \/\/ ...<\/code><\/pre>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0442\u0435\u0441\u0442\u043e\u0432<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">const {   Worker , isMainThread , parentPort } = require('node:worker_threads');  const {   randomBytes , createHash } = require('node:crypto');  const hrtime = process.hrtime.bigint;  const EventEmitter = require('events'); class WorkersPool extends EventEmitter {   #queue;   #workersPool;   #currentWorker;   #onMessageHandler = Symbol('handler');    constructor({queue, workersPool}) {     super();      this.#queue = queue;     this.#workersPool = [...workersPool];      \/\/ \u043d\u0430\u0432\u0435\u0448\u0438\u0432\u0430\u0435\u043c \u0441\u0432\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432 \u0441\u0430\u043c\u043e\u0435 \u043d\u0430\u0447\u0430\u043b\u043e \u0446\u0435\u043f\u043e\u0447\u043a\u0438     this.#workersPool.forEach(worker => {       worker[this.#onMessageHandler] = this.#onMessage.bind(this, worker);       worker.prependListener('message', worker[this.#onMessageHandler]);     });   }    destructor() {     \/\/  \u0433\u0430\u0441\u0438\u043c \u0441\u0432\u043e\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438     this.#workersPool.forEach(worker => {       worker.off('message', worker[this.#onMessageHandler]);       delete worker[this.#onMessageHandler];     });   }    #onMessage(worker) {     \/\/ \u0435\u0441\u043b\u0438 \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u0447\u0442\u043e-\u0442\u043e \u0435\u0441\u0442\u044c - \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0432\u044b\u0437\u0432\u0430\u0432\u0448\u0435\u043c\u0443     const msg = this.#queue.shift();     if (msg) {       worker.postMessage(msg);     }     \/\/ \u0435\u0441\u043b\u0438 \u043d\u0435\u0442 - \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0435\u0433\u043e \u0436\u0434\u0430\u0442\u044c \u0432 \u043f\u0443\u043b\u0435     else {       this.#workersPool.push(worker);     }   }    postMessage(msg) {     \/\/ \u0434\u043e\u0441\u0442\u0430\u0435\u043c \u0438\u0437 \u043f\u0443\u043b\u0430 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u044b\u0439 \u0432\u043e\u0440\u043a\u0435\u0440     const worker = this.#workersPool.pop();     if (worker) {       worker.postMessage(msg);     }     else {       \/\/ \u0435\u0441\u043b\u0438 \u0435\u0433\u043e \u043d\u0435\u0442 - \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u0438       this.#queue.push(msg);     }   } }  if (isMainThread) {   const tsg = hrtime();   const messages = Array(1 &lt;&lt; 12).fill().map(_ => randomBytes(1 &lt;&lt; 16));   console.log('generated:', Number(hrtime() - tsg)\/1e6 | 0, 'ms');    const hashes = messages.map(() => undefined);   let remain;    const workers = [];   let active = 1;   let tsh;    let pool; \/\/ \u044d\u0442\u043e \u043d\u0430\u0448 \u043f\u0443\u043b   process     .on('test:start', () => {       hashes.fill();       remain = hashes.length;            \/\/ \u043f\u0443\u043b \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u0441 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u043e\u0447\u0435\u0440\u0435\u0434\u044c\u044e       const Pow2Buffer = require('.\/Pow2Buffer');       pool = new WorkersPool({         queue : new Pow2Buffer(8, 16)       , workersPool : workers.slice(0, active)       });        \/\/ \u0444\u0438\u043a\u0441\u0438\u0440\u0443\u0435\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043d\u0430 \u043d\u0430\u0447\u0430\u043b\u043e \u0442\u0435\u0441\u0442\u0430       workers.forEach(worker => worker.eLU = worker.performance.eventLoopUtilization());       tsh = hrtime();       messages.forEach((data, id) => {         pool.postMessage({id, data});       });     })     .on('test:end', () => {       const duration = hrtime() - tsh;       workers.forEach(worker => worker.util = worker.performance.eventLoopUtilization(worker.eLU).utilization);       const avg = workers.slice(0, active).reduce((sum, worker) => sum + worker.util, 0)\/active;        console.log(         'hashed ' + active.toString().padStart(2) + ':'       , (Number(duration)\/1e6 | 0).toString().padStart(4)       , 'ms | ' + (avg * 100 | 0) + ' | '       , workers.map(           worker => (worker.util * 100 | 0).toString().padStart(2)         ).join(' ')       );        if (active &lt; n) {         pool.destructor(); \/\/ \u0437\u0430\u0447\u0438\u0449\u0430\u0435\u043c \u043f\u0443\u043b         active++;         process.emit('test:start');       }       else {         process.exit();       }     });    const n = 16;   Promise.all(     Array(n).fill().map(_ => {       return new Promise((resolve, reject) => {         const worker = new Worker(__filename);         worker           .on('online', () => resolve(worker))           .on('message', ({id, hash}) => {             hashes[id] = hash;             if (!--remain) {               process.emit('test:end');             }           });       });         })   )     .then((result) => {       workers.push(...result);       process.emit('test:start');     }); } else {   parentPort.on('message', ({id, data}) => {     parentPort.postMessage({id, hash : createHash('sha256').update(data).digest('hex')});   }); }<\/code><\/pre>\n<pre><code>generated: 278 ms hashed  1: 1449 ms | 82 |  82  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 hashed  2:  701 ms | 82 |  81 84  0  0  0  0  0  0  0  0  0  0  0  0  0  0 hashed  3:  485 ms | 81 |  78 79 85  0  0  0  0  0  0  0  0  0  0  0  0  0 hashed  4:  370 ms | 79 |  77 79 78 81  0  0  0  0  0  0  0  0  0  0  0  0 hashed  5:  347 ms | 68 |  66 64 70 69 72  0  0  0  0  0  0  0  0  0  0  0 hashed  6:  360 ms | 57 |  56 59 53 52 57 62  0  0  0  0  0  0  0  0  0  0 hashed  7:  310 ms | 54 |  54 50 54 50 56 55 58  0  0  0  0  0  0  0  0  0 hashed  8:  312 ms | 46 |  40 45 47 50 43 45 44 50  0  0  0  0  0  0  0  0 hashed  9:  311 ms | 42 |  35 42 42 44 38 41 44 57 38  0  0  0  0  0  0  0 hashed 10:  301 ms | 36 |  35 36 31 34 40 38 37 38 36 39  0  0  0  0  0  0 hashed 11:  312 ms | 32 |  27 31 32 32 29 29 37 32 35 35 30  0  0  0  0  0 hashed 12:  338 ms | 30 |  26 34 24 38 27 31 39 28 25 27 30 31  0  0  0  0 hashed 13:  321 ms | 27 |  23 24 23 26 26 24 32 30 26 28 28 31 25  0  0  0 hashed 14:  316 ms | 29 |  28 21 27 39 26 29 30 18 25 36 29 37 25 33  0  0 hashed 15:  314 ms | 26 |  24 29 28 28 18 28 28 37 17 17 30 25 27 28 32  0 hashed 16:  344 ms | 28 |  23 24 27 28 26 35 23 36 22 37 26 43 22 23 25 23<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><figcaption>Queue vs Round-Robin<\/figcaption><\/figure>\n<p>\u041f\u0440\u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u043d\u0435 \u043c\u0435\u043d\u044c\u0448\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u044f\u0434\u0435\u0440 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u0430 <strong>\u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0441 \u043e\u0431\u0449\u0435\u0439 \u043e\u0447\u0435\u0440\u0435\u0434\u044c\u044e \u0432\u044b\u0438\u0433\u0440\u044b\u0432\u0430\u0435\u0442<\/strong> \u043f\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043f\u0440\u0438 \u0431\u043e\u043b\u0435\u0435 \u0440\u0430\u0432\u043d\u043e\u043c\u0435\u0440\u043d\u043e\u0439 \u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043c\u0435\u043d\u044c\u0448\u0435\u0439 \u0441\u0440\u0435\u0434\u043d\u0435\u0439 \u0443\u0442\u0438\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u0442\u043e\u043a\u043e\u0432.<\/p>\n<h3>\u041a\u0430\u043d\u0430\u043b\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u0432<\/h3>\n<p>\u0412\u043f\u0440\u043e\u0447\u0435\u043c, \u0432 \u044d\u0442\u043e\u0439 \u0440\u0430\u0434\u0443\u0436\u043d\u043e\u0439 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0435 \u0435\u0441\u0442\u044c \u0438 \u0442\u043e\u043b\u0438\u043a\u0430 \u043f\u0435\u0447\u0430\u043b\u0438. \u0421\u0440\u0435\u0434\u043d\u044f\u044f \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0430 \u043f\u043e\u0442\u043e\u043a\u0430\u0445 \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u043b\u0430\u0441\u044c \u0440\u043e\u0432\u043d\u043e \u0437\u0430 \u0441\u0447\u0435\u0442 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043c\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u043c \u0438\u0445 \u0442\u0435\u043f\u0435\u0440\u044c \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c &#8212; \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0445\u043e\u0440\u043e\u0448\u043e \u044d\u0442\u043e \u0432\u0438\u0434\u043d\u043e \u043f\u0440\u0438 \u043c\u0430\u043b\u043e\u043c \u0438\u0445 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435.<\/p>\n<p>\u042d\u0442\u043e \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0435\u0442\u0441\u044f \u0442\u0435\u043c, \u0447\u0442\u043e \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043f\u043e\u0442\u043e\u043a \u0437\u0430\u043c\u0435\u0442\u043d\u043e \u0432\u044b\u0440\u043e\u0441\u043b\u0430 \u0438\u0437-\u0437\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438  \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u043f\u0440\u0438\u043a\u043b\u0430\u0434\u043d\u0443\u044e \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c, \u043d\u043e \u0438 \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c\u0441\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u043e\u0439 \u043e\u0447\u0435\u0440\u0435\u0434\u0438 &#8212; \u043a\u0430\u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c, <strong>\u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u043e\u0442\u0432\u0435\u0442<\/strong>, \u043e\u0442\u043c\u0435\u0447\u0430\u044f \u0441\u043b\u0443\u0436\u0435\u0431\u043d\u044b\u0439 \u043f\u043e\u0442\u043e\u043a \u043a\u0430\u043a \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u044b\u0439.<\/p>\n<p>\u041d\u043e \u0432\u0435\u0434\u044c \u043c\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u0442\u043e \u043c\u043e\u0436\u0435\u043c <strong>\u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u043a\u0430\u043d\u0430\u043b\u044b \u043e\u0431\u043c\u0435\u043d\u0430 \u0441 \u043f\u043e\u0442\u043e\u043a\u043e\u043c<\/strong>, \u043d\u0430 \u043a\u0430\u043d\u0430\u043b \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u043a\u0430\u043d\u0430\u043b \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u0432 \u043a\u0430\u043a \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u044b <a href=\"https:\/\/nodejs.org\/dist\/latest-v16.x\/docs\/api\/worker_threads.html#class-messagechannel\">MessageChannel<\/a>. \u0418 \u0431\u0443\u0434\u0435\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u0438\u0433\u043d\u0430\u043b \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u043f\u043e\u0442\u043e\u043a\u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u043e\u043a\u0440\u0430\u0442\u043d\u043e \u043f\u0440\u0438 <strong>\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0441\u0440\u0430\u0437\u0443 \u043f\u0430\u0447\u043a\u0438 \u0437\u0430\u0434\u0430\u0447<\/strong>, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c\u044b\u0445 \u0447\u0435\u0440\u0435\u0437 <a href=\"https:\/\/nodejs.org\/dist\/latest-v16.x\/docs\/api\/worker_threads.html#workerreceivemessageonportport\">receiveMessageOnPort<\/a>.<\/p>\n<figure class=\"\"><figcaption>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 MessageChannel<\/figcaption><\/figure>\n<p>\u0421\u0445\u0435\u043c\u0430\u0442\u0438\u0447\u043d\u043e <code>MessageChannel<\/code> \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d, \u043a\u0430\u043a \u0434\u0432\u0430 \u043f\u043e\u0440\u0442\u0430, \u043e\u0434\u0438\u043d \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u0438\u0442 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c\u0443 (\u0438\u043b\u0438 \u043b\u044e\u0431\u043e\u043c\u0443 \u0434\u0440\u0443\u0433\u043e\u043c\u0443) \u043f\u043e\u0442\u043e\u043a\u0443, \u0430 \u0434\u0440\u0443\u0433\u043e\u0439 &#8212; \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u043c\u0443. \u0412 \u043a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u043d\u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u043a\u0430\u043a \u043d\u0435\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u043e \u043f\u0438\u0441\u0430\u0442\u044c, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0437\u0430 \u043d\u0438\u043c \u0441\u0442\u043e\u0438\u0442 \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u0442\u0430\u043a \u0438 \u0447\u0438\u0442\u0430\u0442\u044c \u0438\u0437 \u043d\u0435\u0433\u043e &#8212; \u043f\u043e\u043b\u0443\u0447\u0430\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0438\u043b\u0438 \u0432\u044b\u0447\u0438\u0442\u044b\u0432\u0430\u044f \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e.<\/p>\n<p>\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0439 \u043d\u0430\u043c \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u043f\u043e\u0442\u043e\u043a\u0430 <code>parentPort<\/code> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0440\u043e\u0432\u043d\u043e \u0442\u0430\u043a\u043e\u0439 \u0436\u0435 &#171;\u043f\u043e\u043b\u043e\u0432\u0438\u043d\u043a\u043e\u0439&#187; \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432 <code>Worker<\/code> \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430  <code>MessageChannel.<\/code><\/p>\n<figure class=\"full-width\"><figcaption>\u0421\u0445\u0435\u043c\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u043a\u0430\u043d\u0430\u043b\u0430\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u0432<\/figcaption><\/figure>\n<p>\u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0433\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430, \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 \u0434\u0430\u0442\u0430-\u043f\u043e\u0440\u0442 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 \u0441\u0440\u0430\u0437\u0443 <strong>\u0431\u043b\u043e\u043a<\/strong><\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-338750","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/338750","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=338750"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/338750\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=338750"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=338750"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=338750"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}