Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Як передати дані між потоками?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)Основний спосіб - передача повідомлень через `postMessage()` / `parentPort`; для одноразової передачі при старті використовують `workerData`, а для швидкого обміну великими даними без копіювання - `SharedArrayBuffer` або Transferable-об'єкти. **Ключове:** потоки не бачать глобальних змінних одне одного - будь-який обмін іде через явно надані канали.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## 1. Як влаштована взаємодія між потоками Кожен потік (`Worker`) у Node.js: - має **свій власний контекст** (не ділить змінні з іншими), - виконується **в межах одного процесу**, - може **обмінюватися повідомленнями** з головним потоком через **message passing** (передачу повідомлень), - за потреби - **ділити пам'ять** через `SharedArrayBuffer`. Тобто: > Потоки не бачать глобальних змінних одне одного, > але можуть спілкуватися через спеціально надані канали. ## 2. Базовий спосіб - **передача повідомлень (message passing)** Це найпоширеніший і найбезпечніший спосіб обміну даними між потоками. ### Приклад: **main.js** ```javascript const { Worker } = require('worker_threads'); const worker = new Worker('./worker.js'); // Надсилаємо дані в потік worker.postMessage({ name: 'Tim', numbers: [1, 2, 3] }); // Отримуємо відповідь worker.on('message', (result) => { console.log('Відповідь від потоку:', result); }); ``` **worker.js** ```javascript const { parentPort } = require('worker_threads'); // Отримуємо повідомлення від основного потоку parentPort.on('message', (data) => { const sum = data.numbers.reduce((a, b) => a + b, 0); parentPort.postMessage({ greeting: `Привіт, ${data.name}!`, sum }); }); ``` Як це працює: - `main.js` створює потік і надсилає дані за допомогою `postMessage()`. - Потік отримує дані через `parentPort.on('message', ...)`. - Після обчислень - надсилає відповідь назад через `parentPort.postMessage()`. ## 3. Передача даних при запуску - `workerData` Ти можеш передати дані **один раз під час створення потоку**, використовуючи параметр `workerData`. ### Приклад: **main.js** ```javascript const { Worker } = require('worker_threads'); const worker = new Worker('./worker.js', { workerData: { n: 5 } }); worker.on('message', result => console.log('Результат:', result)); ``` **worker.js** ```javascript const { workerData, parentPort } = require('worker_threads'); let fact = 1; for (let i = 1; i <= workerData.n; i++) fact *= i; parentPort.postMessage({ factorial: fact }); ``` Тут дані (`n: 5`) передаються одразу під час створення воркера, без `postMessage()`. ## 4. Спільне використання пам'яті - **SharedArrayBuffer** Це просунутий спосіб, що дозволяє **ділити пам'ять між потоками**, щоб уникнути копіювання даних і прискорити обмін. Використовується, коли: - потрібно часто обмінюватися великими масивами, - важлива максимальна продуктивність, - допустимі низькорівневі операції. ### Приклад: **main.js** ```javascript const { Worker } = require('worker_threads'); const shared = new SharedArrayBuffer(4 * Int32Array.BYTES_PER_ELEMENT); const sharedArray = new Int32Array(shared); sharedArray[0] = 42; const worker = new Worker('./worker.js', { workerData: shared }); worker.on('exit', () => { console.log('Змінено воркером:', sharedArray[0]); // 84 }); ``` **worker.js** ```javascript const { workerData } = require('worker_threads'); const arr = new Int32Array(workerData); arr[0] *= 2; // Модифікуємо спільне значення ``` Тут: - `SharedArrayBuffer` створює спільну область пам'яті, доступну обом потокам. - Зміни, зроблені в одному потоці, видно в іншому **негайно**. - Можна використовувати `Atomics` для безпечних операцій (щоб уникнути гонок даних). ## 5. Передача великих даних без копіювання - **Transferable objects** Node.js підтримує **передачу "за посиланням"** деяких об'єктів (замість копіювання), наприклад `ArrayBuffer`, `MessagePort`, `SharedArrayBuffer`. Приклад передачі великого буфера без копіювання: ```javascript const { Worker } = require('worker_threads'); const buffer = new ArrayBuffer(8); const worker = new Worker('./worker.js'); worker.postMessage(buffer, [buffer]); // передача за посиланням (buffer тепер недоступний у main) worker.on('message', () => console.log('Воркер отримав буфер!')); ``` **worker.js** ```javascript const { parentPort } = require('worker_threads'); parentPort.on('message', (buffer) => { console.log('Буфер отримано у воркері, розмір:', buffer.byteLength); parentPort.postMessage('OK'); }); ``` Після передачі об'єкт стає **"detached"** (недоступний у відправника). ## 6. Зведення способів передачі даних | Спосіб | Напрямок | Особливості | |---|---|---| | `postMessage()` / `on('message')` | двосторонньо | Найпоширеніший спосіб, безпечний | | `workerData` | у воркер під час створення | Одноразова передача при запуску | | `SharedArrayBuffer` | спільна пам'ять | Дуже швидко, але вимагає обережності | | `Transferable objects` | одноразова передача за посиланням | Без копіювання, після передачі джерело втрачає доступ | ## 7. Як обрати спосіб | Сценарій | Що використати | |---|---| | Звичайні дані (об'єкти, JSON, числа) | `postMessage()` | | Передача параметрів при запуску | `workerData` | | Обмін великою кількістю даних | `SharedArrayBuffer` | | Максимальна продуктивність, без копіювання | `Transferable objects` | | Кілька воркерів, незалежні задачі | `postMessage()` + черги повідомлень | ## Підсумок | Характеристика | Значення | |---|---| | Потоки ізольовані одне від одного | Так | | Спільні змінні доступні? | Ні | | Як спілкуються | Через `message passing` або спільну пам'ять | | Передача при старті | Через `workerData` | | Розділювана пам'ять | `SharedArrayBuffer` + `Atomics` | | Безпечний варіант | `postMessage()` | **Висновок:** > У Node.js потоки не діляться станом напряму. > > Для обміну даними використовують: > > - **повідомлення (postMessage / parentPort)** - безпечний, простий спосіб; > - **спільну пам'ять (SharedArrayBuffer)** - швидкий, але вимагає акуратності; > - **transferable об'єкти** - для ефективної передачі великих структур.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.