在node.js中没有sleep()/等待互斥体,所以如何处理大的IO任务?
我有一大堆我需要检查的文件名,但是我也需要响应networking客户端。 最简单的方法是执行:
for(var i = 0; i <array.length; i ++){ fs.readFile(array [i],function(err,data){...}); }
,但数组可以是任意长度,比如说100000,所以一次执行100000个读取操作并不是一个好主意,另一方面,执行fs.readFileSync()可能需要很长时间。 还在callback中启动下一个fs.readFile(),如下所示:
var Idx = 0; 函数checkFile(){ fs.readFile(array [Idx],function(err,data){ IDX ++; if(Idx <array.length){ checkFile(); } else { Idx = 0; setTimeout(checkFile,10000); //开始在一秒钟内检查文件 } }); }
也不是最好的select,因为数组[]不断更新的networking客户端 – 一些项目删除,新添加等。
在node.js中完成这样一个任务的最好方法是什么?
你应该坚持你的第一个解决scheme( fs.readFile
)。 对于文件I / O,node.js使用线程池。 原因是大多数unix内核不提供文件系统的高效的asynchronousAPI。 即使您同时启动10,000次读取,实际上只有几次读取将会运行,其余的将在队列中等待。
为了使这个答案更有趣,我再次浏览节点的代码,以确保事情没有改变。
长话短说,文件I / O使用阻塞系统调用,并且由最多4个并发线程的线程池来完成 。
重要的代码是在libuv抽象的libeio中 。 所有的I / O代码都是由请求排队的macros包装的。 例如:
eio_req *eio_read (int fd, void *buf, size_t length, off_t offset, int pri, eio_cb cb, void *data, eio_channel *channel) { REQ (EIO_READ); req->int1 = fd; req->offs = offset; req->size = length; req->ptr2 = buf; SEND; }
REQ
准备请求并SEND
队列。 我们最终在etp_maybe_start_thread
结束:
static unsigned int started, idle, wanted = 4; (...) static void etp_maybe_start_thread (void) { if (ecb_expect_true (etp_nthreads () >= wanted)) return; (...)
队列保持4个线程运行来处理请求。 当我们的读取请求被最终执行时,eio只需使用从unistd.h中read
的块:
case EIO_READ: ALLOC (req->size); req->result = req->offs >= 0 ? pread (req->int1, req->ptr2, req->size, req->offs) : read (req->int1, req->ptr2, req->size); break;