2016-01-31 10 views
8

Dies ist eine konzeptionelle Abfrage bezüglich der Optimierung auf Systemebene. Mein Verständnis durch das Lesen der NodeJS-Dokumentation ist, dass Pipes praktisch sind, um die Flusskontrolle in Streams durchzuführen.Führt die .pipe() -Memcpy in node.js aus?

Hintergrund: Ich habe Mikrofonstrom kommen und ich wollte eine zusätzliche Kopie vermeiden, um MIPS Gesamtsystem zu erhalten. Ich verstehe, dass dies für Audiostreams nicht sehr viel MIPS ist, selbst wenn es eine Memcopy unter der Haube gab, aber ich habe auch eine Erweiterung geplant, um in Kamerarahmen mit 30 fps und UHD-Auflösung zu streamen. Das Erstellen mehrerer Kopien von Pixeldaten mit UHD-Auflösung mit 30 fps ist sehr ineffizient.

Beispielcode:

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; 

Hier sind die Fragen:

  1. der Lage sein, Flusskontrolle durchzuführen, funktioniert die source.pipe (DEST) führt eine Memcpy aus dem Quellenspeicher an den Zielspeicher unter der Haube ODER würde es die Referenz im Speicher an das Ziel übergeben?
  2. Der kommentierte Code enthält eine PassThrough-Klasseninstanziierung - ich gehe derzeit davon aus, dass PassThrough auch Memcopies verursacht, und deshalb speichere ich eine Memcpy-Operation im gesamten System, weil ich die obigen Kommentare hinzugefügt habe?
  3. Wenn ich eine Pipe zwischen einem Prozess und einem gestützten untergeordneten Prozess (mit child_process.spawn() wie in How to transfer/stream big data from/to child processes in node.js without using the blocking stdio? gezeigt) erstellen musste, nehme ich an, dass definitiv in memcpy resultiert? Gibt es überhaupt eine Referenz, anstatt zu kopieren?
  4. Unterscheidet sich dieses Verhalten von Betriebssystem zu Betriebssystem? Ich nehme an, es sollte OS-agnostisch sein, aber frag es trotzdem.

Vielen Dank im Voraus für Ihre Hilfe. Es wird meiner Architektur sehr helfen.

Antwort

4

einige Referenz der 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

Ich habe versucht, eine komplizierte/riesige explaination auf theese Basis zu schreiben und einige andere Dateien aber ich kam zu dem Schluss es wäre, Am besten, um Ihnen eine Zusammenfassung davon zu geben, wie meine Erfahrung/Messwert mir Knoten intern funktioniert:

Pipe verbindet einfach Streams, so dass es aussieht, als ob .on("data", …) von .write(…) aufgerufen wird, ohne dass irgendetwas dazwischen aufgebläht ist.

jetzt müssen wir die js Welt von der C++/c Welt trennen.
Beim Umgang mit Daten in js verwenden wir Puffer. https://github.com/nodejs/node/blob/master/src/node_buffer.cc
sie repräsentieren einfach zugewiesenen Speicher mit einigen Süßigkeiten an der Spitze, um damit zu arbeiten.

Wenn Sie stdout eines Prozesses an einen Listener von .on("data", …) anschließen, kopiert er den eingehenden Chunk in ein Buffer-Objekt zur weiteren Verwendung innerhalb der js-Welt.
innerhalb der js Welt haben Sie Methoden wie .pause() usw. (wie Sie in Knoten Dampf-API-Dokumentation sehen können) zu verhindern, dass der Prozess Speicher essen, falls eingehende Daten schneller als seine verarbeitet fließt.

Die Verbindung von stdout eines Prozesses und zum Beispiel eines ausgehenden tcp-Ports durch eine Pipe führt zu einer ähnlichen Verbindung wie nginx. es verbindet diese Ströme, als würden sie direkt miteinander kommunizieren, indem sie eingehende Daten direkt in den ausgehenden Strom kopieren.

Sobald Sie einen Stream anhalten, verwendet der Knoten die interne Pufferung, falls er den eingehenden Stream nicht pausieren kann.

so für Ihr Szenario sollten Sie nur testen.
versuchen, Daten über einen eingehenden Stream im Knoten zu empfangen, den Stream anzuhalten und zu sehen, was passiert.
Ich bin mir nicht sicher, ob der Knoten die interne Pufferung verwenden wird oder ob der Prozess, den Sie ausführen möchten, angehalten wird, bis er weiter Daten senden kann.
Ich erwarte, dass der Prozess angehalten wird, bis Sie den Stream fortsetzen.

für die Übertragung von großen Bildern empfehle ich, sie in Chunks zu übertragen oder direkt an einen ausgehenden Port zu leiten.

der Chunk Weg würde Ihnen erlauben, die Daten an mehrere Clients gleichzeitig zu senden und würde den Speicherbedarf ziemlich niedrig halten.

PS sollten Sie einen Blick auf diesen Kern nehmen, die ich gerade gefunden: https://gist.github.com/joyrexus/10026630
es erklärt ausführlich, wie Sie mit den Strömen in Wechselwirkung treten können