Що таке 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 за замовчуванням):
- Поки програма чекає завершення однієї операції введення-виведення, вона не може виконувати інші задачі.
Приклад псевдокоду:
const data = fs.readFileSync('file.txt'); // блокує виконання
console.log('Файл прочитано'); // виконається лише після читання файлуУ цей час CPU простоює, чекаючи завершення операції читання.
Неблокуючий I/O (non-blocking I/O)
Node.js виконує I/O асинхронно: він не чекає завершення операції, а продовжує виконувати решту коду.
const fs = require('fs');
fs.readFile('file.txt', 'utf8', (err, data) => {
console.log('Файл прочитано');
});
console.log('Код не блокується!');Що відбувається:
- Node.js починає читати файл.
- Операція йде у фоновий потік (через libuv).
- Програма не чекає, а виконує наступний код.
- Коли читання завершено, викликається callback / Promise / async/await - і результат повертається.
Як це працює всередині
Node.js побудований на механізмі Event Loop та бібліотеці libuv:
- libuv керує чергами подій і потоками.
- Коли операція I/O завершена, у event loop потрапляє подія про готовність результату.
- Callback (або
then,await) виконується, коли дані доступні.
Отже, навіть один потік може обробляти тисячі з'єднань одночасно.
Приклад: сервер із blocking vs non-blocking
Блокуючий приклад
const fs = require('fs');
const http = require('http');
http.createServer((req, res) => {
const data = fs.readFileSync('data.txt'); // блокує!
res.end(data);
}).listen(3000);Кожен запит чекатиме завершення читання файлу. При 1000 запитах черга «захлинеться».
Неблокуючий приклад
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 і мікросервісів
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.