javascript — Node.js fs.open () зависает после попытки открыть более 4 именованных каналов (FIFO)

У меня есть процесс 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

Repl.it ссылка


ПРИМЕЧАНИЕ. Следующая часть этого вопроса связана с тем, что я уже пытался ответить на вопрос, но, возможно, не имеет к нему никакого отношения.


Два интересных факта с этим сценарием

  • при записи дважды в одном из FIFO, (т.е. echo hello > fifo) Узел тогда может открыть еще один fifo, но больше не получает от того, в котором мы написали
  • когда поток чтения создается путем непосредственного указания пути к fifo (вместо fd), скрипт больше не блокируется, но, по-видимому, больше не получает то, что написано в любом из 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 ++ скрипт успешно открывает сто пятнадцать.

Обратите внимание, что между этими двумя реализациями есть несколько отличий. В С ++ один,

  • Сценарий только открыть FIFOS,
  • нет никаких предварительных для чтения,
  • и нет многопоточности

#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 и не зависает молча …)


Как видите, я пытался искать во многих направлениях, и все это привело меня к моему вопросу:

Знаете ли вы, что может вызвать такое поведение?

Спасибо

1

Решение

Поэтому я задал вопрос на 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.
});
2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]