在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;