几天来,我一直在寻找一个有效的错误解决方案
错误:EMFILE,打开的文件太多
似乎很多人都有同样的问题。通常的答案是增加文件描述符的数量。所以,我试过了:
sysctl -w kern.maxfiles=20480
缺省值为10240。在我看来,这有点奇怪,因为我在目录中处理的文件数量低于10240。更奇怪的是,在增加了文件描述符的数量之后,我仍然收到相同的错误。
第二个问题:
经过多次搜索,我找到了一个解决“打开文件太多”问题的方法:
var requestBatches = {};
function batchingReadFile(filename, callback) {
// First check to see if there is already a batch
if (requestBatches.hasOwnProperty(filename)) {
requestBatches[filename].push(callback);
return;
}
// Otherwise start a new one and make a real request
var batch = requestBatches[filename] = [callback];
FS.readFile(filename, onRealRead);
// Flush out the batch on complete
function onRealRead() {
delete requestBatches[filename];
for (var i = 0, l = batch.length; i < l; i++) {
batch[i].apply(null, arguments);
}
}
}
function printFile(file){
console.log(file);
}
dir = "/Users/xaver/Downloads/xaver/xxx/xxx/"
var files = fs.readdirSync(dir);
for (i in files){
filename = dir + files[i];
console.log(filename);
batchingReadFile(filename, printFile);
不幸的是,我仍然收到相同的错误。
这段代码有什么问题?
还有一种可能性,到目前为止,在任何答案中都没有考虑或讨论过:符号链接循环。
节点的递归文件系统监控器似乎无法检测和处理符号链接的循环。所以你可以很容易地用任意高的nfiles ulimit触发这个错误,只需运行:
mkdir a
mkdir a/b
cd a/b
ln -s .. c
GNU find会注意到符号链接循环并中止:
$ find a -follow
a
a/b
find: File system loop detected; ‘a/b/c’ is part of the same file system loop as ‘a’.
但是节点不会。如果你在树上设置了一个手表,它会抛出一个EMFILE,太多打开文件的错误。
在有包含关系的node_modules中也会发生这种情况:
parent/
package.json
child/
package.json
这也是我在做项目时遇到的问题。
对于同一个问题,我做了上面提到的所有事情,但都不起作用。我试了下,它工作100%。简单的配置更改。
选项1:设置限制(大多数情况下都不起作用)
user@ubuntu:~$ ulimit -n 65535
检查电流限制
user@ubuntu:~$ ulimit -n
1024
选项2:将可用限制增加到例如65535
user@ubuntu:~$ sudo nano /etc/sysctl.conf
添加下面的行
fs.file-max = 65535
运行此命令以刷新新的配置
user@ubuntu:~$ sudo sysctl -p
编辑以下文件
user@ubuntu:~$ sudo vim /etc/security/limits.conf
向它添加以下行
root soft nproc 65535
root hard nproc 65535
root soft nofile 65535
root hard nofile 65535
编辑以下文件
user@ubuntu:~$ sudo vim /etc/pam.d/common-session
把这一行加进去
session required pam_limits.so
注销并登录并尝试以下命令
user@ubuntu:~$ ulimit -n
65535
选项3:只添加这一行
DefaultLimitNOFILE=65535
到 /etc/systemd/system.conf 和 /etc/systemd/user.conf
我自己刚刚写了一小段代码来解决这个问题,所有其他的解决方案看起来都太重量级了,需要你改变程序结构。
这个解决方案只是暂停任何f。readFile或fs。writeFile调用,以便在任何给定时间运行的次数不超过设定的数目。
// Queuing reads and writes, so your nodejs script doesn't overwhelm system limits catastrophically
global.maxFilesInFlight = 100; // Set this value to some number safeish for your system
var origRead = fs.readFile;
var origWrite = fs.writeFile;
var activeCount = 0;
var pending = [];
var wrapCallback = function(cb){
return function(){
activeCount--;
cb.apply(this,Array.prototype.slice.call(arguments));
if (activeCount < global.maxFilesInFlight && pending.length){
console.log("Processing Pending read/write");
pending.shift()();
}
};
};
fs.readFile = function(){
var args = Array.prototype.slice.call(arguments);
if (activeCount < global.maxFilesInFlight){
if (args[1] instanceof Function){
args[1] = wrapCallback(args[1]);
} else if (args[2] instanceof Function) {
args[2] = wrapCallback(args[2]);
}
activeCount++;
origRead.apply(fs,args);
} else {
console.log("Delaying read:",args[0]);
pending.push(function(){
fs.readFile.apply(fs,args);
});
}
};
fs.writeFile = function(){
var args = Array.prototype.slice.call(arguments);
if (activeCount < global.maxFilesInFlight){
if (args[1] instanceof Function){
args[1] = wrapCallback(args[1]);
} else if (args[2] instanceof Function) {
args[2] = wrapCallback(args[2]);
}
activeCount++;
origWrite.apply(fs,args);
} else {
console.log("Delaying write:",args[0]);
pending.push(function(){
fs.writeFile.apply(fs,args);
});
}
};