2016-01-31 46 views
8

這是關於系統級優化的概念性查詢。通過閱讀NodeJS文檔,我的理解是管道可以方便地對流進行流量控制。.pipe()是否在node.js中執行memcpy?

背景:我有麥克風流進來,我想避免額外的複製操作來保存整個系統的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; 

這裏有問題:

  1. 爲了能夠進行流量控制,莫非source.pipe(DEST)從源存儲器到執行的memcpy目的地存儲器下的內存或它會傳遞內存中的引用到目的地?
  2. 評論代碼包含一個PassThrough類實例化 - 我目前假設PassThrough也會導致memcopies,所以我在整個系統中保存一個memcpy操作,因爲我在上面的註釋中添加了?
  3. 如果我必須在Process和Spawned Child進程之間創建一個管道(使用child_process.spawn(),如How to transfer/stream big data from/to child processes in node.js without using the blocking stdio?所示),我認爲這肯定會導致memcpy?無論如何要做出參考而不是複製?
  4. 此行爲不同於OS到OS?我認爲它應該是操作系統不可知論的,但無論如何都要問這個問題。

在此先感謝您的幫助。這將有助於我的架構很多。

回答

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(…)調用,而沒有任何臃腫之處。

現在我們需要將js世界從C++/c世界中分離出來。
當我們使用緩衝區處理js中的數據時。 https://github.com/nodejs/node/blob/master/src/node_buffer.cc
它們只是表示分配的內存上面有一些糖果來操作它。

如果將某個進程的stdout連接到某個.on("data", …)偵聽器,它會將傳入的塊複製到Buffer對象中以供在js世界中進一步使用。
在js世界裏,你有類似.pause()等的方法(正如你可以在節點的steam api文檔中看到的),以防止進程吃掉內存,以防輸入數據比其處理速度快。

連接進程的標準輸出和例如通過管道的輸出tcp端口將導致類似於nginx操作的連接。它將連接這些數據流,就好像它們直接將傳入數據直接複製到傳出數據流中一樣。

只要暫停流,節點將使用內部緩衝,以防其無法暫停傳入流。

所以對於你的場景你應該只是做測試。
嘗試通過節點中的傳入流接收數據,暫停流並查看會發生什麼。
我不確定節點是否使用內部緩衝,或者如果您嘗試運行的進程只是暫停,直到它可以繼續發送數據。
我期望過程停止,直到您繼續流。

爲了傳輸巨大的圖像,我建議將它們分塊傳輸或將它們直接傳輸到傳出端口。

塊的方式將允許您一次發送數據到多個客戶端,並將保持內存佔用相當低。

PS,你應該看看這個要旨我剛剛發現:https://gist.github.com/joyrexus/10026630
它深入闡述瞭如何與流

互動