Выполняет ли node.js асинхронное чтение / запись файла в основном потоке? - PullRequest
0 голосов
/ 12 сентября 2018

Я думал, что асинхронная обработка, такая как чтение файла, обрабатывается в другом потоке и уведомляет основной поток о завершении чтения в другом потоке.

Я попытался выполнить следующее.

const fs = require("fs")

console.time(1)
fs.readFile("largefile", x => console.timeEnd(1))

Это показывает 1500ms.

Во-вторых, я попробовал следующее.

const fs = require("fs")

console.time(1)
fs.readFile("largefile", x => console.timeEnd(1))

// block main thread 1sec
const s = Date.now()
while(Date.now() - s < 1000);

Это покажет 1500ms, если асинхронный процесс обрабатывается в другом потоке.Однако я получил 2500ms.

Я попробовал другой.

const fs = require("fs")

console.time(1)
fs.readFile("largefile", x => console.timeEnd(1))

setInterval(() => {
    const s = Date.now()
    while(Date.now() - s < 100);
}, 100)

Я жду несколько минут, но сообщения нет.

Обрабатывает ли nodejs интенсивную обработкув главном потоке?

Стоит ли использовать child_process, когда мне нужно читать и писать слишком много больших файлов?

1 Ответ

0 голосов
/ 12 сентября 2018

Ввод / вывод выполняется с использованием неблокирующих операций под крышками (вместо того, чтобы занимать основной поток); Однако I / O завершение (например, обратные вызовы) выполняется в потоке, в котором была запущена операция I / O (в вашем примере, в одном главном потоке JavaScript, поскольку вы не используете * 1003). * рабочие ). Если вы насыщаете этот поток, у него не будет возможности обработать обратные вызовы.

Основные проблемы в вашем примере:

  1. Вы используете вспомогательную функцию readFile для одновременного чтения большого файла в память.

  2. Ваш тест является синтетическим, он выполняет чрезвычайно ресурсоемкие задачи, которые вряд ли будут моделировать характеристики вашего реального приложения.

Обрабатывает ли 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 для асинхронного выполнения операций уже обрабатывают его более эффективно, чем рабочие потоки.

...