0

想象一下,您想下载图像或文件,这将是互联网教您继续前进的第一种方式:

request(url, function(err, res, body) {
    fs.writeFile(filename, body);
});

但这不是将所有数据累积body在内存中吗?会pipe更有效吗?

request(url).pipe(fs.createWriteStream(filename));

或者这是在内部以类似的方式处理,无论如何缓冲流,使其无关紧要?

此外,如果我想使用回调而不是body因为你仍然可以 pipe),这个内存缓冲区还会被填满吗?

我问是因为第一个(回调)方法允许我链接下载而不是并行启动它们(*),但我不想填充我也不会使用的缓冲区。因此,如果我不想诉诸诸如异步之类的花哨的东西只是为了使用队列来防止这种情况,我需要回调。

(*) 这很糟糕,因为如果request在它们完成之前你的文件太多,那么异步特性request将导致节点在过量事件和内存丢失中窒息而死。首先你会得到这些:

"possible EventEmitter memory leak detected. 11 listeners added. Use emitter.setMaxListeners() to increase limit."

当拉伸它时,500 个管道请求将填满你的内存并崩溃节点。这就是为什么你需要回调而不是管道,所以你知道什么时候开始下一个文件。

4

2 回答 2

3

但这不是将所有数据累积在body中,填满内存吗?

是的,很多操作比如你的第一个片段缓冲数据到内存中进行处理。是的,这会使用内存,但至少很方便,有时需要,具体取决于您打算如何处理该数据。如果您想加载 HTTP 响应并将正文解析为 JSON,这几乎总是通过缓冲来完成,尽管可以使用流式解析器,但它要复杂得多并且通常是不必要的。大多数 JSON 数据都不够大,因此流式传输是一个巨大的胜利。

或者这是在内部以类似的方式处理,使这无关紧要?

不,将整个数据作为字符串提供给您的 API 使用缓冲而不是流式传输。

但是,多媒体数据,是的,您无法将其实际缓冲到内存中,因此流式传输更合适。此外,数据往往是不透明的(您不解析或处理它),这也有利于流式传输。

在情况允许的情况下,流式传输很好,但这并不意味着缓冲必然有任何问题。事实是缓冲是绝大多数事情大部分时间的工作方式。从总体上看,流式传输只是一次缓冲 1 个块,并将它们限制在可用资源范围内的某个大小限制。如果您要处理它,某些部分的数据需要在某个时候通过内存。

因为如果你只是一个一个地请求太多的文件,请求的异步性质会导致节点在事件过量和内存丢失中窒息而死。

不确定您在此处说明/询问的确切内容,但是是的,编写有效的程序需要考虑资源和效率。

另请参阅hyperquest README 中 substack 对流式传输/池化的咆哮

于 2013-11-08T01:46:24.343 回答
1

我想出了一个解决方案,使有关记忆的问题变得无关紧要(尽管我仍然很好奇)。

如果我想使用回调而不是body因为你仍然可以 pipe),这个内存缓冲区还会被填充吗?

您不需要callbackfromrequest()即可知道请求何时完成。当“结束”pipe()时,将自行关闭。stream关闭会发出一个事件并且可以被监听:

request(url).pipe(fs.createWriteStream(filename)).on('close', function(){           
    next();
});

现在,您可以将所有请求排队并一一下载文件。

当然,您可以一直使用 8 个并行请求与库(async.queue例如async.

此外,无论如何,您都不会想在多用户系统上的一个技巧中最大化您的系统资源。

于 2013-11-08T03:19:46.797 回答