Javascript fs.readFile非常慢,我是否提出了太多请求?
node.js初学者在此: 一个node.js应用程序从大约30个URL的列表中刮取一个链接数组(linkArray) 每个域/url都有一个对应的(name).json文件,用于检查刮取的链接是否是新的 获取所有页面,将链接刮入数组,然后传递给:Javascript fs.readFile非常慢,我是否提出了太多请求?,javascript,node.js,asynchronous,readfile,Javascript,Node.js,Asynchronous,Readfile,node.js初学者在此: 一个node.js应用程序从大约30个URL的列表中刮取一个链接数组(linkArray) 每个域/url都有一个对应的(name).json文件,用于检查刮取的链接是否是新的 获取所有页面,将链接刮入数组,然后传递给: function checkLinks(linkArray, name){ console.log(name, "checkLinks"); fs.readFile('json/'+name+'.json', 'u
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);
}
});
}
compareAndad()读取:
函数compareAndAdd(arrNew、arrOld、name){
log(名称为“compareAndAdd()”);
如果(!arrOld)变量arrOld=[];
如果(!arrNew)变量arrNew=[];
//比较并删除DUP
函数hasDup(值){
对于(变量i=0;i
checkLinks()是程序挂起的地方,它的速度慢得令人难以置信。我知道fs.readFile每秒会被点击多次,但我知道点击次数不到30次似乎很简单:假设这是一个用于向(可能)数百万用户提供数据的函数。我是否对fs.readFile期望过高,或者(更有可能)是否有另一个组件(如writeFile或其他完全相同的组件)将所有内容都锁定
补充:
使用write/readFileSync会产生很多问题:这个程序本质上是异步的,因为它从外部网站的请求开始,响应时间变化很大,读/写会经常发生冲突。上面的函数确保只在读取给定文件之后才对其进行写操作。(尽管速度非常慢)
而且,这个程序不会自行退出,我也不知道为什么
编辑
我重新编写了程序,先读后同步写,进程缩短到12秒。显然,fs.readFile在多次调用时被挂起。如果多个调用挂起函数,我不知道何时/如何使用异步fs。所有异步
fs
操作都在libuv threa内执行d池,默认大小为4(可以通过将UV\u THREADPOOL\u size
环境变量设置为其他变量来更改)。如果线程池中的所有线程都很忙,则任何fs
操作都将排队
我还应该指出,
fs
不是唯一使用线程池的模块,dns.lookup()
(节点内部使用的默认主机名解析方法)、asynczlib
方法、crypto.randomBytes()
,IIRC还使用了libuv线程池。这只是需要记住的一点。所有异步fs
操作都是在libuv线程池内执行的,libuv线程池的默认大小为4(可以通过将UV\u THREADPOOL\u size
环境变量设置为不同的值来更改)。如果线程池中的所有线程都忙,则任何fs
操作都将排队
我还应该指出,fs
不是唯一使用线程池的模块,dns.lookup()
(节点内部使用的默认主机名解析方法)、asynczlib
方法、crypto.randomBytes()
,IIRC还使用了libuv线程池。这只是需要记住的一点。如果在循环中读取了许多文件(检查链接),首先会调用所有的fs.readFile
函数。只有在调用之后才会处理回调(仅当主函数堆栈为空时才会处理回调).这将导致启动延迟。但不要担心这一点
您指出一个程序永远不会结束。因此,请创建一个计数器,统计对checkLinks
的调用,并在调用回调函数后减少计数器。在回调中,根据0检查计数器,然后执行终结逻辑(我怀疑这可能是对http请求的响应)
实际上,无论您使用的是异步版本还是同步版本,它们都将在相对相同的时间工作。如果您在一个循环中读取了许多文件(检查链接),首先将调用所有的fs.readFile
函数。并且只有在这之后才会处理回调(仅当主函数堆栈为空时才处理它们).这将导致启动延迟。但不要担心这一点
您指出一个程序永远不会结束。因此,请创建一个计数器,统计对checkLinks
的调用,并在调用回调函数后减少计数器。在回调中,根据0检查计数器,然后执行终结逻辑(我怀疑这可能是对http请求的响应)
实际上,使用异步版本还是同步并不重要。它们的工作时间相对相同。FYI,在异步回调中执行
throw err
不会对您有任何好处,因为无法捕获该抛出。您需要在一些console.log()中对每个fs.readFile()
进行计时
并查看它们是否都很慢,或者只有后面的那些很慢,因为线程池很忙,因此您正在等待。我建议输出每个fs.readFile()
操作所需的确切时间。与fs.writeFile()相同
。我们需要看看这是否只是一个线程池争用问题,或者您的读/写速度是否因为某种原因而变慢。另外,当您说“难以置信的慢”时,我们谈论的时间是多少?@jfriend00>4分钟。这些文件有多大?前几次读写是否快了很多?仅供参考,在异步回调中执行throw err
不会对您有任何好处,因为无法捕捉到该抛出。您需要在某些时间内对每个fs.readFile()
进行计时
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;
}