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。
答案 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请求的响应)。
实际上,使用异步版本还是同步并不重要。他们将在相对同一时间工作。