【发布时间】:2019-03-07 14:16:36
【问题描述】:
我有一个 node.js 进程需要从多个命名管道中读取,这些命名管道由不同的其他进程作为 IPC 方法提供。
在从四个以上的 fifo 打开和创建读取流后,我意识到 fs 似乎不再能够打开 fifo 并且只是挂在那里。
考虑到可以毫无问题地同时打开数千个文件(例如,在以下脚本中将mkfifo 替换为touch),这个数字似乎有点低。
我在 MacOS 10.13 上使用 node.js v10.1.0 和在 Ubuntu 16.04 上使用 node.js v8.9.3 进行了测试,结果相同。
错误的脚本
以及显示此行为的脚本:
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
注意,这个问题的以下部分与我已经尝试回答的问题有关,但可能不是它的核心
这个脚本有两个有趣的事实
- 当在一个 FIFO 中写入两次时,(即
echo hello > fifo)节点能够再打开一个 fifo,但不再从我们写入的那个接收到 - 当通过直接提供到 fifo(而不是 fd)的路径来创建读取流时,脚本不再阻塞,但显然不再接收写入任何 FIFO 中的内容
调试信息
然后我尝试验证这是否与某些操作系统限制有关,例如打开的文件描述符的数量。
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++ 中,脚本成功打开了一百个 fifo。
请注意,这两种实现方式之间存在一些差异。在 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;
}
附带说明,需要在执行脚本之前创建 fifo,例如使用
for i in $(seq 0 100); do mkfifo /tmp/tmpfifo/$i; done
潜在的 Node.js 相关问题
经过一番搜索,似乎也与 Node.js Github 上的那个问题有关:
https://github.com/nodejs/node/issues/1941.
但人们似乎在抱怨相反的行为(fs.open() 抛出 EMFILE 错误并且没有静默挂起......)
如您所见,我尝试在多个方向进行搜索,所有这些都将我引向了我的问题:
您知道什么会导致这种行为吗?
谢谢
【问题讨论】:
-
是的,我评论了这种行为,这可能表明这是来自 Node.js。来自 Github 的问题表明他们可能同时实现了某种队列......
-
不,不,没关系,我采取了详尽无遗的立场,但我想它会使长度有点压倒性:|
-
更多的是为了保持评论部分的干净,这样更多的读者不需要阅读无用的评论,如果写了????但是很高兴看到您能够找到解决方案。
标签: javascript c++ node.js fifo ulimit