.pipe() 是否在 node.js 中执行 memcpy?
Does the .pipe() perform a memcpy in node.js?
这是关于系统级优化的概念性查询。我通过阅读 NodeJS 文档的理解是,管道可以很方便地对流进行流量控制。
背景:我有麦克风流进入,我想避免额外的复制操作以保存整个系统 MIPS。我知道对于音频流来说,即使在引擎盖下有 memcopy,也不会花费大量的 MIPS,但我也有一个扩展计划,以 30fps 和 UHD 分辨率在相机帧中流式传输。以 30fps 制作多个 UHD 分辨率像素数据的副本效率极低,因此需要一些建议。
示例代码:
var spawn = require('child_process').spawn
var PassThrough = require('stream').PassThrough;
var ps = null;
//var audioStream = new PassThrough;
//var infoStream = new PassThrough;
var start = function() {
if(ps == null) {
ps = spawn('rec', ['-b', 16, '--endian', 'little', '-c', 1, '-r', 16000, '-e', 'signed-integer', '-t', 'raw', '-']);
//ps.stdout.pipe(audioStream);
//ps.stderr.pipe(infoStream);
exports.audioStream = ps.stdout;
exports.infoStream = ps.stderr;
}
};
var stop = function() {
if(ps) {
ps.kill();
ps = null;
}
};
//exports.audioStream = audioStream;
//exports.infoStream = infoStream;
exports.startCapture = start;
exports.stopCapture = stop;
问题如下:
- 为了能够执行流量控制,source.pipe(dest) 是在幕后执行从源内存到目标内存的 memcpy,还是将内存中的引用传递到目标?
- 评论的代码包含一个 PassThrough class 实例化 - 我目前假设 PassThrough 也会导致 memcopies,所以我在整个系统中保存了一个 memcpy 操作,因为我在上面的评论中添加了?
- 如果我必须在一个进程和一个生成的子进程之间创建一个管道(使用 child_process.spawn(),如 How to transfer/stream big data from/to child processes in node.js without using the blocking stdio? 所示),我认为这肯定会导致 memcpy?有没有办法使它成为一个参考而不是复制?
- 此行为与 OS 和 OS 有何不同?我认为它应该是 OS 不可知论者,但无论如何都要问这个问题。
在此先感谢您的帮助。它将对我的架构有很大帮助。
一些url供参考:https://github.com/nodejs/node/
https://github.com/nodejs/node/blob/master/src/stream_wrap.cc
https://github.com/nodejs/node/blob/master/src/stream_base.cc
https://github.com/libuv/libuv/blob/v1.x/src/unix/stream.c
https://github.com/libuv/libuv/blob/v1.x/src/win/stream.c
我尝试根据 theese 和其他一些文件写一个复杂/庞大的解释,但是我得出的结论是最好给你一个总结,说明我的经验/阅读告诉我节点内部是如何工作的:
pipe 简单地连接流,使其看起来好像 .on("data", …)
被 .write(…)
调用,中间没有任何臃肿的东西。
现在我们需要将 js 世界与 c++/c 世界分开。
在 js 中处理数据时,我们使用缓冲区。 https://github.com/nodejs/node/blob/master/src/node_buffer.cc
它们只是表示已分配的内存,顶部有一些糖果可以使用它进行操作。
如果您将进程的标准输出连接到某个 .on("data", …)
侦听器,它会将传入的块复制到 Buffer 对象中,以便在 js 世界中进一步使用。
在 js 世界中,你有像 .pause()
等方法(正如你在 nodes steam api 文档中看到的那样),以防止进程占用内存,以防输入数据流速度快于其处理速度。
连接进程的标准输出,例如通过管道的传出 tcp 端口将产生类似于 nginx 操作方式的连接。它将连接这些流,就好像它们会通过将传入数据直接复制到传出流来直接相互对话一样。
一旦您暂停流,节点将使用内部缓冲以防无法暂停传入流。
所以对于您的场景,您应该只进行测试。
尝试通过节点中的传入流接收数据,暂停流,看看会发生什么。
我不确定节点是否会使用内部缓冲,或者您尝试 运行 的进程是否会停止,直到它可以继续发送数据。
我希望这个过程会停止,直到你继续播放。
对于传输大图像,我建议将它们分块传输或直接通过管道传输到传出端口。
块方式允许您一次将数据发送到多个客户端,并且会保持内存占用非常低。
PS 你应该看看我刚刚发现的这个要点:https://gist.github.com/joyrexus/10026630
它深入解释了如何与流交互
这是关于系统级优化的概念性查询。我通过阅读 NodeJS 文档的理解是,管道可以很方便地对流进行流量控制。
背景:我有麦克风流进入,我想避免额外的复制操作以保存整个系统 MIPS。我知道对于音频流来说,即使在引擎盖下有 memcopy,也不会花费大量的 MIPS,但我也有一个扩展计划,以 30fps 和 UHD 分辨率在相机帧中流式传输。以 30fps 制作多个 UHD 分辨率像素数据的副本效率极低,因此需要一些建议。
示例代码:
var spawn = require('child_process').spawn
var PassThrough = require('stream').PassThrough;
var ps = null;
//var audioStream = new PassThrough;
//var infoStream = new PassThrough;
var start = function() {
if(ps == null) {
ps = spawn('rec', ['-b', 16, '--endian', 'little', '-c', 1, '-r', 16000, '-e', 'signed-integer', '-t', 'raw', '-']);
//ps.stdout.pipe(audioStream);
//ps.stderr.pipe(infoStream);
exports.audioStream = ps.stdout;
exports.infoStream = ps.stderr;
}
};
var stop = function() {
if(ps) {
ps.kill();
ps = null;
}
};
//exports.audioStream = audioStream;
//exports.infoStream = infoStream;
exports.startCapture = start;
exports.stopCapture = stop;
问题如下:
- 为了能够执行流量控制,source.pipe(dest) 是在幕后执行从源内存到目标内存的 memcpy,还是将内存中的引用传递到目标?
- 评论的代码包含一个 PassThrough class 实例化 - 我目前假设 PassThrough 也会导致 memcopies,所以我在整个系统中保存了一个 memcpy 操作,因为我在上面的评论中添加了?
- 如果我必须在一个进程和一个生成的子进程之间创建一个管道(使用 child_process.spawn(),如 How to transfer/stream big data from/to child processes in node.js without using the blocking stdio? 所示),我认为这肯定会导致 memcpy?有没有办法使它成为一个参考而不是复制?
- 此行为与 OS 和 OS 有何不同?我认为它应该是 OS 不可知论者,但无论如何都要问这个问题。
在此先感谢您的帮助。它将对我的架构有很大帮助。
一些url供参考:https://github.com/nodejs/node/
https://github.com/nodejs/node/blob/master/src/stream_wrap.cc
https://github.com/nodejs/node/blob/master/src/stream_base.cc
https://github.com/libuv/libuv/blob/v1.x/src/unix/stream.c
https://github.com/libuv/libuv/blob/v1.x/src/win/stream.c
我尝试根据 theese 和其他一些文件写一个复杂/庞大的解释,但是我得出的结论是最好给你一个总结,说明我的经验/阅读告诉我节点内部是如何工作的:
pipe 简单地连接流,使其看起来好像 .on("data", …)
被 .write(…)
调用,中间没有任何臃肿的东西。
现在我们需要将 js 世界与 c++/c 世界分开。
在 js 中处理数据时,我们使用缓冲区。 https://github.com/nodejs/node/blob/master/src/node_buffer.cc
它们只是表示已分配的内存,顶部有一些糖果可以使用它进行操作。
如果您将进程的标准输出连接到某个 .on("data", …)
侦听器,它会将传入的块复制到 Buffer 对象中,以便在 js 世界中进一步使用。
在 js 世界中,你有像 .pause()
等方法(正如你在 nodes steam api 文档中看到的那样),以防止进程占用内存,以防输入数据流速度快于其处理速度。
连接进程的标准输出,例如通过管道的传出 tcp 端口将产生类似于 nginx 操作方式的连接。它将连接这些流,就好像它们会通过将传入数据直接复制到传出流来直接相互对话一样。
一旦您暂停流,节点将使用内部缓冲以防无法暂停传入流。
所以对于您的场景,您应该只进行测试。
尝试通过节点中的传入流接收数据,暂停流,看看会发生什么。
我不确定节点是否会使用内部缓冲,或者您尝试 运行 的进程是否会停止,直到它可以继续发送数据。
我希望这个过程会停止,直到你继续播放。
对于传输大图像,我建议将它们分块传输或直接通过管道传输到传出端口。
块方式允许您一次将数据发送到多个客户端,并且会保持内存占用非常低。
PS 你应该看看我刚刚发现的这个要点:https://gist.github.com/joyrexus/10026630
它深入解释了如何与流交互