У меня есть процесс node.js, который должен читать из нескольких именованных каналов, питаемых другими процессами, в качестве метода IPC.
После того как я открыл и создал потоки чтения из более чем четырех FIFO, я понял, что fs, похоже, больше не может открывать FIFO и просто зависает там.
Кажется, что это число немного мало, учитывая, что можно без проблем открывать тысячи файлов одновременно (например, путем замены mkfifo
от touch
в следующем сценарии).
Я тестировал с node.js v10.1.0 на MacOS 10.13 и с node.js v8.9.3 на Ubuntu 16.04 с тем же результатом.
Неисправный скрипт
И скрипт, который отображает это поведение:
var fs = require("fs");
var net = require("net");
var child_process = require('child_process');
var uuid = function() {
for (var i = 0, str = ""; i < 32; i++) {
var number = Math.floor(Math.random() * 16);
str += number.toString(16);
}
return str;
}
function setupNamedPipe(cb) {
var id = uuid();
var fifoPath = "/tmp/tmpfifo/" + id;
child_process.exec("mkfifo " + fifoPath, function(error, stdout, stderr) {
if (error) {
return;
}
fs.open(fifoPath, 'r+', function(error, fd) {
if (error) {
return;
}
var stream = fs.createReadStream(null, {
fd
});
stream.on('data', function(data) {
console.log("FIFO data", data.toString());
});
stream.on("close", function(){
console.log("close");
});
stream.on("error", function(error){
console.log("error", error);
});
console.log("OK");
cb();
});
});
}
var i = 0;
function loop() {
++i;
console.log("Open ", i);
setupNamedPipe(loop);
}
child_process.exec("mkdir -p /tmp/tmpfifo/", function(error, stdout, stderr) {
if (error) {
return;
}
loop();
});
Этот сценарий не убирается за ним, не забудьте rm -r /tmp/tmpfifo
ПРИМЕЧАНИЕ. Следующая часть этого вопроса связана с тем, что я уже пытался ответить на вопрос, но, возможно, не имеет к нему никакого отношения.
Два интересных факта с этим сценарием
echo hello > fifo
) Узел тогда может открыть еще один fifo, но больше не получает от того, в котором мы написалиОтладочная информация
Затем я попытался проверить, может ли это быть связано с каким-то ограничением ОС, например, количеством открытых файловых дескрипторов.
Ouput of ulimit -a
на Mac есть
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
max locked memory (kbytes, -l) unlimited
max memory size (kbytes, -m) unlimited
open files (-n) 256
pipe size (512 bytes, -p) 1
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 1418
virtual memory (kbytes, -v) unlimited
Ничто не указывает на некоторое ограничение в 4.
C ++ предварительно
Затем я попытался написать аналогичный скрипт на C ++.
В C ++ скрипт успешно открывает сто пятнадцать.
Обратите внимание, что между этими двумя реализациями есть несколько отличий. В С ++ один,
#include <string>
#include <cstring>
#include <sys/stat.h>
#include <fcntl.h>
#include <iostream>
int main(int argc, char** argv)
{
for (int i=0; i < 100; i++){
std::string filePath = "/tmp/tmpfifo/" + std::to_string(i);
auto hehe = open(filePath.c_str(), O_RDWR);
std::cout << filePath << " " << hehe << std::endl;
}
return 0;
}
В качестве примечания, необходимо создать fifos перед выполнением сценария, например, с помощью
for i in $(seq 0 100); do mkfifo /tmp/tmpfifo/$i; done
Потенциальная проблема, связанная с Node.js
После небольшого поиска, кажется, это также связано с этой проблемой на Github Node.js:
https://github.com/nodejs/node/issues/1941.
Но люди, похоже, жалуются на противоположное поведение (fs.open () выдает ошибки EMFILE и не зависает молча …)
Как видите, я пытался искать во многих направлениях, и все это привело меня к моему вопросу:
Знаете ли вы, что может вызвать такое поведение?
Спасибо
Поэтому я задал вопрос на Node.js Github, https://github.com/nodejs/node/issues/23220
Из решения:
Работа с FIFO в настоящее время немного сложнее.
open()
системные вызовы блокируются в FIFO по умолчанию до тех пор, пока не будет открыта другая сторона канала. Поскольку Node.js использует пул потоков для операций файловой системы, открывая несколько каналов, гдеopen()
звонки не заканчиваются исчерпывает этот поток потоков.Решение состоит в том, чтобы открыть файл в неблокирующем режиме, но это затрудняет то, что другой
fs
вызовы не создаются с учетом неблокирующих файловых дескрипторов;net.Socket
есть, однако.Итак, решение будет выглядеть примерно так:
fs.open('path/to/fifo/', fs.constants.O_RDONLY | fs.constants.O_NONBLOCK, (err, fd) => { // Handle err const pipe = new net.Socket({ fd }); // Now `pipe` is a stream that can be used for reading from the FIFO. });
Других решений пока нет …