У меня есть процесс node.js, который должен читать из нескольких именованных каналов, передаваемых разными другими процессами, в качестве метода IPC.
Я понял, что после открытия и создания потоков чтения из более чем четырех ярусов, что fsКажется, больше не сможет открыть fifos и просто висит там.
Кажется, что это число немного мало, учитывая, что можно без проблем открыть тысячи файлов одновременно (например, заменив 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
Repl.it link
ПРИМЕЧАНИЕ. Следующая часть этого вопроса связана с тем, что я уже пытался ответить на вопрос, но, возможно, не является центральным для него
Два интересных факта с этим сценарием
- при записи дважды в один из FIFO (т. Е.
echo hello > fifo
) узел затем может открыть еще один fifo, но больше не получает оттот, в котором мы написали - , когда поток чтения создается непосредственно провидиномЕсли указать путь к fifo (вместо fd), скрипт больше не блокируется, но, по-видимому, больше не получает то, что написано в любом из FIFO
Debugинформация
Затем я попытался проверить, может ли это быть связано с каким-либо ограничением ОС, например, количеством открытых файловых дескрипторов.
Выход 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 ++ скрипт успешно открывает сто пятнадцать.
Обратите внимание, что между этими двумя реализациями есть несколько отличий.В C ++ one,
- скрипт только открывает fifo,
- нет предварительного чтения,
- и нет многопоточности
#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;
}
В качестве примечания, перед выполнением сценария необходимо создать пятерки, например, с помощью
for i in $(seq 0 100); do mkfifo /tmp/tmpfifo/$i; done
Потенциальная проблема, связанная с Node.js
После небольшого поиска, кажется, это также связано с этой проблемой на Gitub Node.js:
https://github.com/nodejs/node/issues/1941.
Но люди, похоже, жалуются на противоположное поведение (fs.open () выдает ошибки EMFILE и не зависает молча ...)
Как видите, япытался искать во многих направлениях, и все это привело меня к моему вопросу:
Знаете ли вы, что может вызвать такое поведение?
Спасибо