Що таке libuv і як він забезпечує асинхронний ввід/вивід у Node.js?
libuv: Асинхронний I/O двигун Node.js
libuv — це багатоплатформена бібліотека на C, яка забезпечує цикл подій, пул потоків та асинхронні I/O можливості, що підтримують Node.js. Без libuv неможливо було б реалізувати неблокуючу модель I/O в Node.js.
Огляд архітектури
┌──────────────────────────────────────────┐
│ Ваш код Node.js │
├──────────────────────────────────────────┤
│ Ядро Node.js (JS API) │
│ http, fs, crypto, net, dns, child... │
├──────────────────────────────────────────┤
│ Прив'язки Node.js (C++) │
├──────────────────────────────────────────┤
│ libuv (C бібліотека) │
│ ┌─────────────┐ ┌────────────────────┐ │
│ │ Цикл подій │ │ Пул потоків │ │
│ │ (I/O poll) │ │ (за замовчуванням 4│ │
│ └─────────────┘ └────────────────────┘ │
├──────────────────────────────────────────┤
│ Операційна система │
│ epoll (Linux) kqueue (macOS) IOCP │
└──────────────────────────────────────────┘Що надає libuv
1. Цикл подій
Цикл подій опитує події I/O та виконує зворотні виклики, коли операції завершуються. Він абстрагує специфічні для ОС асинхронні механізми:
- Linux:
epoll - macOS / BSD:
kqueue - Windows:
IOCP(Порти завершення I/O)
2. Пул потоків
Деякі операції не можуть бути асинхронними на рівні ОС (файлова система на деяких платформах, DNS запити, криптографія). libuv надає пул потоків (за замовчуванням: 4 потоки) для обробки цих операцій:
// Ці операції використовують пул потоків libuv:
fs.readFile() // файловий I/O
crypto.pbkdf2() // ресурсоємна криптографія
dns.lookup() // DNS розв'язування
zlib compression // стиснення// Мережева I/O (TCP, UDP) НЕ використовує пул потоків
// Вона використовує асинхронні механізми ОС безпосередньо (epoll/kqueue)
http.get() // без пулу потоків!
net.connect() // без пулу потоків!Розмір пулу потоків
# За замовчуванням 4 потоки, можна збільшити:
UV_THREADPOOL_SIZE=16 node server.js// Або під час виконання (повинно бути встановлено перед будь-якою асинхронною роботою):
process.env.UV_THREADPOOL_SIZE = '16';Збільшуйте його, коли у вас багато одночасних:
- Операцій з файловою системою
- Викликів
crypto.pbkdf2()/crypto.scrypt() - DNS запитів
Як працює асинхронна операція
1. JS викликає fs.readFile()
↓
2. Прив'язка Node передає запит до libuv
↓
3. libuv подає запит до пулу потоків (файл) або ОС (мережа)
↓
4. Основний потік продовжує (цикл подій працює)
↓
5. Пул потоків / ОС завершує роботу
↓
6. libuv ставить зворотний виклик у чергу
↓
7. Цикл подій підбирає зворотний виклик → виконує в JSПрактичний вплив: Виснаження пулу потоків
// Якщо UV_THREADPOOL_SIZE=4 і ви робите:
for (let i = 0; i < 100; i++) {
crypto.pbkdf2(password, salt, 10000, 512, 'sha512', callback);
}
// Тільки 4 виконуються паралельно! Інші ставляться в чергу.
// Рішення: збільшити UV_THREADPOOL_SIZElibuv Хендли та Запити
libuv використовує дві абстракції:
- Хендли — довгоживучі об'єкти (TCP сервери, таймери, спостерігачі за файлами)
- Запити — короткочасні операції (запит на запис, DNS запит)
const server = net.createServer(); // Хендл (довгоживучий)
server.listen(3000);
fs.readFile('./file', cb); // Запит (однократний)Резюме
libuv є C двигуном за Node.js. Він реалізує:
- Цикл подій з нативним асинхронним опитуванням I/O ОС
- Пул потоків для блокуючих операцій
- Хендли та запити для управління асинхронною роботою
Розуміння libuv допомагає зрозуміти чому Node.js швидкий для I/O, чому є обмеження пулу потоків, і як насправді працює цикл подій.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.