Ввод / вывод выполняется с использованием неблокирующих операций под крышками (вместо того, чтобы занимать основной поток); Однако I / O завершение (например, обратные вызовы) выполняется в потоке, в котором была запущена операция I / O (в вашем примере, в одном главном потоке JavaScript, поскольку вы не используете * 1003). * рабочие ). Если вы насыщаете этот поток, у него не будет возможности обработать обратные вызовы.
Основные проблемы в вашем примере:
Вы используете вспомогательную функцию readFile
для одновременного чтения большого файла в память.
Ваш тест является синтетическим, он выполняет чрезвычайно ресурсоемкие задачи, которые вряд ли будут моделировать характеристики вашего реального приложения.
Обрабатывает ли nodejs интенсивную обработку в основном потоке?
Некоторые части вспомогательных функций, такие как readFile
, реализованы в потоке, в котором вы их вызвали (основной поток в вашем примере), да. readFile
реализован в JavaScript с использованием fs.read
, и он не запрашивает следующую порцию данных, пока не будет обработана предыдущая порция; размер фрагментов по умолчанию (на момент написания статьи) составляет 8 КБ (8 192) байта.
Вы можете увидеть это в источнике в:
lib/fs.js
, который показывает readFile
с использованием объекта ReadFileContext
.
internal/fs/read_file_context.js
, который показывает реализацию объекта ReadFileContext
, где мы можем видеть его чтение в виде фрагментов через fs.read
.
Это означает, что если основной поток заблокирован (ваш второй кодовый блок) или находится под чрезвычайно большой нагрузкой (ваш третий кодовый блок), он очень медленно обрабатывает обратные вызовы один раз на 8k read
, и это резко влияет на выполнение функции удобства:
- Ваш второй кодовый блок (с занятым ожиданием 1000 мс) предотвращает обработку первого обратного вызова для первых 8k данных, поэтому он задерживает процесс чтения на все 1000 мс, в течение которых он блокируется.
- Ваш третий кодовый блок (с
setInterval
ожиданием вызова 100 мс каждые 100 мс) соответствует реализации readFile
, чтобы ввести задержку ~ 100 мс между каждым 8кб блоком, считанным из файла. Файл любого значительного размера будет очень долго читать со скоростью ~ 820 байт / с.
Опять же, ваш тест синтетический. Блокировка основного потока даже на 100 мс одновременно является необычной.
Должен ли я использовать child_process, когда мне нужно прочитать и записать слишком много больших файлов?
Нет. Просто сделайте это в блоках разумного размера, используя основные операции ввода-вывода (read
, write
или потоков ), а не с помощью вспомогательных функций как readFile
. Использование дочернего процесса для этого было бы, по крайней мере, так же плохо, если не хуже, чем использование рабочего потока, и команда разработчиков Node.js может сказать это в документации worker threads :
Рабочие полезны для выполнения ресурсоемких операций JavaScript; не используйте их для ввода-вывода, поскольку встроенные механизмы Node.js для асинхронного выполнения операций уже обрабатывают его более эффективно, чем рабочие потоки.