1

我需要检查大量文件名,但我还需要响应网络客户端。最简单的方法是执行:

    for(var i=0;i < array.length;i++) {
        fs.readFile(array[i], function(err, data) {...});
    }

,但数组可以是任意长度,比如 100000,因此一次执行 100000 次读取不是一个好主意,另一方面,执行 fs.readFileSync() 可能需要太长时间。还在回调中启动下一个 fs.readFile() ,如下所示:

    var idx = 0;
    功能检查文件(){
       fs.readFile(array[Idx], function (err, data) {
          idx++;
          if (Idx < array.length) {
             检查文件();
          } 别的 {
             idx = 0;
             设置超时(检查文件,10000);// 在一秒后开始检查文件
          }
       });
    }

也不是最佳选择,因为网络客户端会不断更新 array[] - 删除一些项目,添加新项目等等。

在 node.js 中完成此类任务的最佳方法是什么?

4

1 回答 1

3

您应该坚持您的第一个解决方案 ( fs.readFile)。对于文件 I/O,node.js 使用线程池。原因是大多数 unix 内核没有为文件系统提供高效的异步 API。即使您同时启动 10,000 次读取,也只有少数读取会实际运行,其余的将在队列中等待。

为了使这个答案更有趣,我再次浏览了节点的代码以确保事情没有改变。

长话短说,文件 I/O 使用阻塞系统调用,并且由最多具有 4 个并发线程的线程池完成

重要的代码在libeio中,由libuv抽象出来。所有 I/O 代码都由对请求进行排队的宏包装。例如:

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 只需使用readunistd.h 中的块:

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;
于 2012-08-09T11:19:30.177 回答