几天来,我一直在寻找一个有效的错误解决方案

错误: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);

不幸的是,我仍然收到相同的错误。 这段代码有什么问题?


当前回答

我安装了守望者,改变限制等,它不工作在Gulp。

不过,重新启动iterm2实际上有所帮助。

其他回答

以@blak3r的回答为基础,以下是我使用的一些速记,以防它有助于其他诊断:

如果你试图调试一个正在耗尽文件描述符的node .js脚本,这里有一行给你问题节点进程使用的lsof的输出:

openFiles = child_process.execSync(`lsof -p ${process.pid}`);

这将同步运行由当前运行的Node.js进程过滤的lsof,并通过缓冲区返回结果。

然后使用console.log(openFiles.toString())将缓冲区转换为字符串并记录结果。

你读的文件太多了。节点异步读取文件,它会一次读取所有文件。所以你可能读到了10240的限制。

看看这是否有效:

var fs = require('fs')
var events = require('events')
var util = require('util')
var path = require('path')

var FsPool = module.exports = function(dir) {
    events.EventEmitter.call(this)
    this.dir = dir;
    this.files = [];
    this.active = [];
    this.threads = 1;
    this.on('run', this.runQuta.bind(this))
};
// So will act like an event emitter
util.inherits(FsPool, events.EventEmitter);

FsPool.prototype.runQuta = function() {
    if(this.files.length === 0 && this.active.length === 0) {
        return this.emit('done');
    }
    if(this.active.length < this.threads) {
        var name = this.files.shift()

        this.active.push(name)
        var fileName = path.join(this.dir, name);
        var self = this;
        fs.stat(fileName, function(err, stats) {
            if(err)
                throw err;
            if(stats.isFile()) {
                fs.readFile(fileName, function(err, data) {
                    if(err)
                        throw err;
                    self.active.splice(self.active.indexOf(name), 1)
                    self.emit('file', name, data);
                    self.emit('run');

                });
            } else {
                self.active.splice(self.active.indexOf(name), 1)
                self.emit('dir', name);
                self.emit('run');
            }
        });
    }
    return this
};
FsPool.prototype.init = function() {
    var dir = this.dir;
    var self = this;
    fs.readdir(dir, function(err, files) {
        if(err)
            throw err;
        self.files = files
        self.emit('run');
    })
    return this
};
var fsPool = new FsPool(__dirname)

fsPool.on('file', function(fileName, fileData) {
    console.log('file name: ' + fileName)
    console.log('file data: ', fileData.toString('utf8'))

})
fsPool.on('dir', function(dirName) {
    console.log('dir name: ' + dirName)

})
fsPool.on('done', function() {
    console.log('done')
});
fsPool.init()

吹风笛,你只需要零钱

FS.readFile(filename, onRealRead);

=>

var bagpipe = new Bagpipe(10);

bagpipe.push(FS.readFile, filename, onRealRead))

风笛帮助你限制平行动作。详情:https://github.com/JacksonTian/bagpipe

我通过更新watchman解决了这个问题

 brew install watchman

我自己刚刚写了一小段代码来解决这个问题,所有其他的解决方案看起来都太重量级了,需要你改变程序结构。

这个解决方案只是暂停任何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);
        });
    }
};