fs.readFile非常慢,我提出的请求太多了吗?

时间:2017-02-18 23:26:34

标签: javascript node.js asynchronous readfile

node.js在这里初学者:

node.js应用程序从~30个网址的列表中抓取一个链接数组(linkArray)。

每个域/ url都有一个相应的(名称).json文件,用于检查被删除的链接是否是新的。

获取所有页面,将链接刮入数组,然后传递给:

function checkLinks(linkArray, name){
    console.log(name, "checkLinks");
    fs.readFile('json/'+name+'.json', 'utf8', function readFileCallback(err, data){
        if(err && err.errno != -4058) throw err;
        if(err && err.errno == -4058){
            console.log(name+'.json', " is NEW .json");
            compareAndAdd(linkArray, {linkArray: []}.linkArray, name);
        }
        else{
            //file EXISTS
            compareAndAdd(linkArray, JSON.parse(data).linkArray, name);
        }
    });
}

compareAndAdd()读取:

function compareAndAdd(arrNew, arrOld, name){   
    console.log(name, "compareAndAdd()");
    if(!arrOld) var arrOld = [];
    if(!arrNew) var arrNew = [];

    //compare and remove dups
    function hasDup(value) {
        for (var i = 0; i < arrOld.length; i++)     
            if(value.href == arrOld[i].href)
                if(value.text.length <= arrOld[i].text.length) return false;
            arrOld.push(value);
            return true;
    }
    var rArr = arrNew.filter(hasDup);

    //update existing array;
    if(rArr.length > 0){
        fs.writeFile('json/'+name+'.json', JSON.stringify({linkArray: arrOld}), function (err) {
            if (err) return console.log(err);
            console.log("  "+name+'.json UPDATED');
        });    
    }
    else console.log("  "+name, "no changes, nothing to update");
    return;
}

checkLinks()是程序挂起的地方,它令人难以置信地慢。据我所知,fs.readFile每秒被击中多次,但imo少于30次点击似乎相当微不足道:假设这是一个用于向(可能)数百万用户提供数据的功能。我是否期望fs.readFile过多,或者(更有可能)还有另一个组件(比如writeFile,或者完全不同的东西)将所有内容锁定起来。

补充

使用write / readFileSync会产生很多问题:这个程序本质上是异步的,因为它始于对外部网站的请求,响应时间差异很大,读/写经常会发生冲突。上述功能确保只有在读取之后才能对给定文件进行写入。 (虽然它很慢)

此外,这个程序不会自行退出,我不知道为什么。

修改

我重新编写了程序,先读取然后同步写入,过程时间缩短到~12秒。显然fs.readFile在被多次调用时被挂起了。如果多个调用挂起函数,我不明白何时/如何使用异步fs。

2 个答案:

答案 0 :(得分:2)

所有异步fs操作都在libuv线程池中执行,其默认大小为4(可以通过将UV_THREADPOOL_SIZE环境变量设置为不同来更改)。如果线程池中的所有线程都忙,则任何fs操作都将排队。

我还应该指出fs不是唯一使用线程池的模块,dns.lookup()(节点内部使用的默认主机名解析方法),async zlib方法, crypto.randomBytes(),以及其他一些事情IIRC也使用libuv线程池。这只是要记住的事情。

答案 1 :(得分:0)

如果您在循环中读取了许多文件(checkLinks),首先将调用所有fs.readFile函数。并且只有在处理回调之后(仅当主函数堆栈为空时才处理它们)。这将导致显着的启动延迟。但不要担心这一点。

你指出一个程序永远不会结束。因此,创建一个计数器,计算对checkLinks的调用,并在调用回调函数后减少计数器。在回调内部,检查计数器0,然后完成逻辑(我怀疑这可能是对http请求的响应)。

实际上,使用异步版本还是同步并不重要。他们将在相对同一时间工作。