Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «CPU-bound та I/O-bound задачі». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**CPU-bound задача обмежена швидкістю процесора (важкі обчислення, криптографія, сортування, стиснення), а I/O-bound задача обмежена часом очікування зовнішнього ресурсу (запити до БД, HTTP, читання файлів).** У CPU-bound коді процесор завантажений на 100%, у I/O-bound він майже простоює. Для однопотокового JavaScript це критично: важкі обчислення блокують event loop, тому їх виносять у Web Workers чи Worker Threads, тоді як асинхронний I/O звільняє потік і дає Node.js обслуговувати десятки тисяч одночасних запитів. ```javascript // CPU-bound: потік зайнятий, event loop стоїть for (let i = 0; i < 1e9; i += 1) {} // I/O-bound: потік вільний, поки чекаємо на диск const data = await fs.readFile('large-file.txt', 'utf-8'); ``` **Ключове:** CPU-bound впирається в обчислення і блокує event loop, I/O-bound впирається в очікування і для Node.js майже безкоштовний.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**CPU-bound задача обмежена швидкістю центрального процесора, а I/O-bound задача обмежена часом очікування відповіді від зовнішнього ресурсу.** Це не про те, скільки коду написано, а про те, що саме є вузьким місцем: обчислення чи очікування. У JavaScript ця різниця критична, бо виконання коду однопотокове. ## Теорія ### TL;DR - CPU-bound: швидкість обмежує процесор. Приклади: великі цикли, криптографія, сортування, шифрування, стиснення. - I/O-bound: швидкість обмежує ввід/вивід (I/O, Input/Output). Процесор простоює, поки чекає на відповідь. Приклади: запити до БД, HTTP, читання та запис файлів, мережеві виклики. - CPU-bound код використовує процесор на 100%, I/O-bound майже не використовує його. - JavaScript однопотоковий, тому CPU-bound операція блокує event loop: UI не оновлюється, події не обробляються, сервер не відповідає на інші запити. - Лікування CPU-bound: Web Workers, Worker Threads, child_process, розбиття на чанки, WebAssembly або нативні модулі. - Лікування I/O-bound: асинхронний код, кешування, пул з'єднань, черги. ### Швидкий приклад ```javascript import fs from 'fs/promises'; // CPU-bound: потік зайнятий обчисленням, event loop стоїть console.time('cpu'); let total = 0; for (let i = 0; i < 1e9; i += 1) total += i; console.timeEnd('cpu'); // I/O-bound: потік вільний, поки операційна система читає файл console.time('io'); const data = await fs.readFile('large-file.txt', 'utf-8'); console.timeEnd('io'); ``` ### Що саме обмежує швидкість | Тип задачі | Що обмежує швидкість | Приклади | | --- | --- | --- | | **CPU-bound** | Центральний процесор (CPU), усе впирається в обчислення | Великі цикли, криптографія, сортування, шифрування, стиснення | | **I/O-bound** | Ввід/вивід (I/O, Input/Output), процесор простоює, поки чекає на відповідь від зовнішнього ресурсу | Запити до БД, HTTP, читання та запис файлів, мережеві виклики | ### CPU-bound, задачі, обмежені процесором > Проблема тут, **довгі обчислення**, які займають потік цілком. ```javascript // Важка CPU-задача: обчислення факторіала function factorial(n) { if (n === 1) return 1; return n * factorial(n - 1); } console.time('CPU'); console.log(factorial(50000)); // зависне, стек переповниться console.timeEnd('CPU'); ``` **Чому це погано в JS (Node.js або браузері):** JavaScript **однопотоковий**, і поки виконується важка операція: - UI не оновлюється, - події не обробляються, - сервер не відповідає на інші запити. Рішення: - використати **Web Workers** (у браузері) або **Worker Threads / child_process** (у Node.js); - розбити обчислення на чанки (`setTimeout`, `setImmediate`); - використати **WebAssembly** або нативні модулі на **Rust / C++** для важких розрахунків. ### I/O-bound, задачі, обмежені вводом-виводом > Проблема тут не в процесорі, а в **часі очікування** відгуку зовнішньої системи. ```javascript import fs from 'fs/promises'; console.time('IO'); const data = await fs.readFile('largeFile.txt', 'utf-8'); // чекаємо на диск console.timeEnd('IO'); console.log(data.slice(0, 100)); ``` **Чому це добре для Node.js:** Node.js має **event loop** і **асинхронний I/O**, тому поки файл читається або база відповідає, потік **вільний** і може обслуговувати інші запити. ### Порівняння та аналогія | Параметр | CPU-bound | I/O-bound | | --- | --- | --- | | Затримка спричинена | Обчисленнями | Очікуванням зовнішнього ресурсу | | Використовує CPU | На 100% | Майже не використовує | | Приклади | Стиснення, шифрування, обробка зображень, ML | Запити до БД, API, читання файлів, мережеві операції | | Підходить для Node.js | Погано, якщо без воркерів | Відмінно, завдяки async/await та event loop | | Як пришвидшити | Багатопотоковість, Web Workers, нативні модулі | Асинхронний код, кешування, пул з'єднань | Проста аналогія: - **CPU-bound**: ви самі готуєте складну страву і не можете відволіктися, тобто завантажені на 100%. - **I/O-bound**: ви замовили доставку їжі і просто чекаєте, тобто можете зайнятися іншими справами. ### Як це впливає на JS і Node.js | Сценарій | Що відбувається | | --- | --- | | **CPU-bound код** | Блокує event loop, усі інші операції «висять» | | **I/O-bound код** | Node.js ефективно обробляє десятки тисяч запитів паралельно | Підсумок: | Тип задачі | Приклади | Оптимізація | | --- | --- | --- | | **CPU-bound** | обчислення, сортування, криптографія, рендеринг | Workers, нативний код, розбиття на частини | | **I/O-bound** | HTTP, БД, файли, мережа | async/await, кешування, черги | ### Типові помилки - Вважати, що `async/await` прискорює обчислення. Асинхронність не додає потоків: важкий цикл, обгорнутий у `async`, блокує event loop так само. - Масштабувати CPU-bound сервіс кількістю одночасних запитів. Поки процесор зайнятий одним обчисленням, решта запитів просто стоїть у черзі. - Виносити у Worker Threads тривіальну роботу. Створення воркера і серіалізація даних коштують дорожче за саме обчислення. - Плутати «повільно» з «CPU-bound». Повільний запит до БД, це I/O-bound, і воркери його не пришвидшать: тут допоможуть індекси, кеш і пул з'єднань. - Розбивати обчислення на чанки через `setTimeout(fn, 0)` у Node.js, коли доречніший `setImmediate`, і навпаки в браузері забувати про `requestIdleCallback`.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.