Проверяет понимание влияния блокирующих системных вызовов на планировщик операционной системы и на асинхронное программирование.
Когда поток выполняет блокирующий системный вызов (например, чтение из файла или ожидание сети), он переходит в состояние ожидания. Планировщик операционной системы видит, что поток не готов к выполнению, и переключает процессор на другие готовые потоки. Это эффективно для многопоточных приложений, так как позволяет использовать ресурсы, пока один поток ждет.
Однако в однопоточных средах, таких как JavaScript в браузере или Node.js, блокирующий вызов останавливает весь цикл событий. Пока вызов выполняется, никакие другие задачи не обрабатываются, что приводит к зависанию интерфейса или сервера.
const fs = require('fs');
// Блокирующий вызов
const data = fs.readFileSync('file.txt');
console.log(data);
// Неблокирующий вызов
fs.readFile('file.txt', (err, data) => {
console.log(data);
});
console.log('Продолжаем выполнение');В первом случае программа ждет завершения чтения, во втором — продолжает работать, а колбэк выполнится позже.
В системном программировании блокирующие вызовы упрощают логику, но снижают масштабируемость. В высоконагруженных серверах используют неблокирующие I/O или пулы потоков, чтобы планировщик мог эффективно распределять нагрузку. В асинхронных языках, таких как Go, горутины автоматически переключаются при блокировках, но в JavaScript нужно явно использовать промисы или async/await.
Понимание блокирующих вызовов критично для проектирования отзывчивых приложений. В однопоточных средах избегайте их, используя асинхронные альтернативы, а в многопоточных — учитывайте накладные расходы на переключение контекста.