Skip to main content

Що таке non-blocking I/O?

Що таке I/O

I/O (Input/Output) - це всі операції, у яких програма взаємодіє із зовнішнім світом, а не просто рахує числа в пам'яті:

  • читання й запис файлів (fs.readFile, fs.writeFile),
  • запити до бази даних,
  • HTTP-запити,
  • операції з мережею (TCP/UDP),
  • звернення до API тощо.

Ці операції займають час, бо залежать від диска, мережі або процесора.

Блокуючий I/O (blocking I/O)

У блокуючому підході (наприклад, у Python, PHP, Java за замовчуванням):

  • Поки програма чекає завершення однієї операції введення-виведення, вона не може виконувати інші задачі.

Приклад псевдокоду:

javascript
const data = fs.readFileSync('file.txt'); // блокує виконання console.log('Файл прочитано'); // виконається лише після читання файлу

У цей час CPU простоює, чекаючи завершення операції читання.

Неблокуючий I/O (non-blocking I/O)

Node.js виконує I/O асинхронно: він не чекає завершення операції, а продовжує виконувати решту коду.

javascript
const fs = require('fs'); fs.readFile('file.txt', 'utf8', (err, data) => { console.log('Файл прочитано'); }); console.log('Код не блокується!');

Що відбувається:

  1. Node.js починає читати файл.
  2. Операція йде у фоновий потік (через libuv).
  3. Програма не чекає, а виконує наступний код.
  4. Коли читання завершено, викликається callback / Promise / async/await - і результат повертається.

Як це працює всередині

Node.js побудований на механізмі Event Loop та бібліотеці libuv:

  • libuv керує чергами подій і потоками.
  • Коли операція I/O завершена, у event loop потрапляє подія про готовність результату.
  • Callback (або then, await) виконується, коли дані доступні.

Отже, навіть один потік може обробляти тисячі з'єднань одночасно.

Приклад: сервер із blocking vs non-blocking

Блокуючий приклад

javascript
const fs = require('fs'); const http = require('http'); http.createServer((req, res) => { const data = fs.readFileSync('data.txt'); // блокує! res.end(data); }).listen(3000);

Кожен запит чекатиме завершення читання файлу. При 1000 запитах черга «захлинеться».

Неблокуючий приклад

javascript
const fs = require('fs'); const http = require('http'); http.createServer((req, res) => { fs.readFile('data.txt', (err, data) => { res.end(data); }); }).listen(3000);

Node.js запускає читання файлу й одразу готовий прийняти інші запити. Сервер лишається відзивчивим навіть під високим навантаженням.

Головна відмінність

Тип I/OЯк працюєПроблема / перевага
BlockingВиконує операції послідовноПростоює під час очікування
Non-blockingВиконує операції асинхронно, через event loopВисока продуктивність, масштабованість

Ключові переваги non-blocking I/O в Node.js

  • Висока швидкість відгуку (немає «зависань» під час I/O)
  • Один потік - тисячі запитів
  • Економія ресурсів (менше потоків, менше пам'яті)
  • Ідеально підходить для API, real-time і мікросервісів

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.