.pipe()是否在node.js中执行memcpy?

时间:2016-01-31 06:06:35

标签: node.js pipe v8 libuv

这是关于系统级优化的概念性查询。通过阅读NodeJS文档,我的理解是管道可以方便地对流进行流量控制。

背景:我有麦克风流进来,我想避免额外的复制操作,以节省整体系统MIPS。据我所知,对于音频流来说,即使在引擎盖下有记忆镜,也不会花费大量的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;

以下是问题:

  1. 为了能够执行流控制,source.pipe(dest)是否会执行从源内存到目标内存的memcpy,还是会将内存中的引用传递到目标?
  2. 注释代码包含PassThrough类实例化 - 我目前假设PassThrough也会导致memcopies,所以我在整个系统中保存了一个memcpy操作,因为我在上面的注释中添加了它?
  3. 如果我必须在Process和Spawned Child进程之间创建一个管道(使用How to transfer/stream big data from/to child processes in node.js without using the blocking stdio?中所示的child_process.spawn()),我认为肯定会产生memcpy?反正有没有提到参考而不是复制?
  4. 此行为是否因操作系统而异?我认为它应该是OS不可知的,但无论如何要问这个。
  5. 提前感谢您的帮助。它将对我的架构有很大的帮助。

1 个答案:

答案 0 :(得分:4)

一些网址供参考: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和其他一些文件写一个复杂/巨大的解释但是我得出的结论是,最好给你一个关于我的经验/阅读如何告诉我节点内部工作的总结:

管道只是简单地连接流,使.on("data", …)调用.write(…),而.on("data", …)之间没有任何膨胀。

现在我们需要将js世界与c ++ / c世界分开 在处理js中的数据时,我们使用缓冲区。 https://github.com/nodejs/node/blob/master/src/node_buffer.cc
它们只是代表分配的内存,顶部带有一些糖果来操作它。

如果将进程的stdout连接到某个.pause()侦听器,它会将传入的块复制到Buffer对象中,以便在js世界中进一步使用。
在js世界中你有TWTRLogInButton was created with no completionBlock set之类的方法(正如你在节点中的蒸汽api文档中看到的那样),以防止进程占用内存,以防传入数据的流速超过其处理速度。

连接进程的stdout,例如通过管道传出tcp端口将导致类似于nginx操作的连接。它将连接theese流,就像通过将传入数据直接复制到传出流来直接相互通信一样。

一旦暂停流,节点将使用内部缓冲,以防无法暂停传入流。

因此,对于您的方案,您应该进行测试 尝试通过节点中的传入流接收数据,暂停流并查看发生的情况 我不确定节点是否会使用内部缓冲,或者您尝试运行的进程是否会暂停,直到它可以继续发送数据。
我希望这个过程停止,直到你继续流。

为了传输巨大的图像,我建议将它们分块传输或直接传输到传出端口。

chunk方式允许您一次将数据发送到多个客户端,并将内存占用空间保持在相当低的水平。

PS你应该看看我刚发现的这个要点:https://gist.github.com/joyrexus/10026630
它深入解释了如何与流进行交互