【发布时间】:2016-12-15 17:55:25
【问题描述】:
我正在构建一个将文件从端点 A 传输到端点 B 的服务器。
我想知道 NodeJs 流管道是否是对称的?
如果我执行以下操作:request.get(A).pipe(request.put(B));,它的上传速度是否与下载速度一样快?
我问这个问题,因为我的服务器有一个不对称的连接(它下载比上传快),我尽量避免内存消耗。
【问题讨论】:
我正在构建一个将文件从端点 A 传输到端点 B 的服务器。
我想知道 NodeJs 流管道是否是对称的?
如果我执行以下操作:request.get(A).pipe(request.put(B));,它的上传速度是否与下载速度一样快?
我问这个问题,因为我的服务器有一个不对称的连接(它下载比上传快),我尽量避免内存消耗。
【问题讨论】:
根据节点的documentation on stream#pipe 管道会将读取流切换到流动模式 - 它只会在写入流完成消耗先前的数据包时读取。
readable.pipe() 方法将 Writable 流附加到可读流,使其自动切换到流动模式并将其所有数据推送到附加的 Writable。数据流将被自动管理,以便目标 Writable 流不会被更快的 Readable 流淹没。
因此,由于发送/下载速度不同,您的传输可能是不对称的 - 差异可能会缓冲在 Node 的内存中 - Buffering of streams
缓冲#
Writable 和 Readable 流都将数据存储在内部 可以使用 writable._writableState.getBuffer() 检索的缓冲区 或 readable._readableState.buffer,分别。
可能缓冲的数据量取决于 highWaterMark 选项传递给流构造函数。对于普通流, highWaterMark 选项指定总字节数。对于流 在对象模式下操作,highWaterMark 指定总数 对象。
当实现调用时,数据被缓冲在可读流中 流.推送(块)。如果 Stream 的消费者没有调用 stream.read() ,数据将位于内部队列中,直到它被 消耗。
一旦内部读取缓冲区的总大小达到阈值 由 highWaterMark 指定,流将暂时停止读取 来自底层资源的数据,直到当前缓冲的数据 可以消费(即流将停止调用内部 read._read() 方法,用于填充读取缓冲区)。
当 writable.write(chunk) 时,数据被缓冲在 Writable 流中 方法被重复调用。而内部的总大小 写入缓冲区低于 highWaterMark 设置的阈值,调用 writable.write() 将返回 true。一旦内部的大小 缓冲区达到或超过highWaterMark,将返回false。
流 API 的一个关键目标,尤其是 stream.pipe() 方法,是将数据的缓冲限制在可接受的水平,例如 不同速度的来源和目的地不会压倒 可用内存。
因为 Duplex 和 Transform 流都是可读和可写的, 每个都维护两个单独的内部缓冲区,用于读取和 写作,允许每一方独立于另一方运作 同时保持适当和有效的数据流。为了 例如,net.Socket 实例是 Duplex 流,其 Readable 端 允许消费从套接字接收到的数据并且其可写 side 允许将数据写入套接字。因为数据可能被写入 套接字以比接收数据更快或更慢的速率,它是 重要的是每一方都独立于另一方操作(和缓冲)。
我建议你看看this question这里的主题进一步阐述。
如果您运行以下示例
const http = require('http');
http.request({method:'GET', host:'somehost.com', path: '/cat-picture.jpg'}, (response)=>{
console.log(response);
}).end()
您可以探索底层套接字 - 在我的系统上,它们都具有 highWaterMark : 16384 属性。因此,如果我了解文档和上述问题,在您的情况下,可能会在更快的 GET 套接字 Node.js 级别中缓冲大约 16KB - 下面发生的事情可能高度依赖于您的系统/网络配置。
【讨论】: