配列から読み取り可能なストリームを作成し、値を書き込み可能なストリームにパイプするための最良の方法は何ですか?サブスタックの 例 setIntervalを使用しているのを見てきましたが、間隔値に0を使用して正常に実装できますが、大量のデータを繰り返し処理しており、毎回gcをトリガーすると速度が低下します。
// Working with the setInterval wrapper
var arr = [1, 5, 3, 6, 8, 9];
function createStream () {
var t = new stream;
t.readable = true;
var times = 0;
var iv = setInterval(function () {
t.emit('data', arr[times]);
if (++times === arr.length) {
t.emit('end');
clearInterval(iv);
}
}
}, 0);
// Create the writable stream s
// ....
createStream().pipe(s);
私がやりたいのは、setIntervalなしで値を出力することです。おそらく、次のような非同期モジュールを使用します。
async.forEachSeries(arr, function(item, cb) {
t.emit('data', item);
cb();
}, function(err) {
if (err) {
console.log(err);
}
t.emit('end');
});
この場合、配列を繰り返してデータを出力しますが、値をパイプすることはありません。私はすでにshinoutの ArrayStream を見てきましたが、それはv0.10より前に作成されたものであり、私が探しているよりも少しオーバーヘッドが大きいと思います。
これには ArrayStream を使用することになりました。 GCが頻繁にトリガーされるという問題は解決しました。ノードから再帰的なprocess.nextTickの警告が表示されていたため、ArrayStreamのnextTickコールバックをsetImmediateに変更しました。これにより、警告が修正され、正常に機能しているようです。
この問題は、読み取り可能なストリームを作成して値をプッシュすることで解決できます。
文字列またはバッファの配列を使用している場合、これは機能します。
_'use strict'
const Stream = require('stream')
const readable = new Stream.Readable()
readable.pipe(process.stdout)
const items = ['a', 'b', 'c']
items.forEach(item => readable.Push(item))
// no more data
readable.Push(null)
_
ノート:
readable.pipe(process.stdout)
は、ストリームを「フロー」モードにすることと、readable
からデータを受信するようにprocess.stdout書き込み可能ストリームを設定することの2つのことを行います。Readable#Push
_メソッドは、読み取り可能なストリームの作成者向けであり、ストリームの利用者向けではありません。Readable#Push(null)
を実行する必要があります。文字列でもバッファでもないものの配列からストリームを作成するには、読み取り可能なストリームと書き込み可能なストリームの両方が "オブジェクトモード" である必要があります。以下の例では、次の変更を加えました。
{objectMode: true}
_で初期化します_process.stdout
_にパイプする代わりに、オブジェクトモードの単純な書き込み可能なストリームにパイプします。
_ 'use strict'
const Stream = require('stream')
const readable = new Stream.Readable({objectMode: true})
const writable = new Stream.Writable({objectMode: true})
writable._write = (object, encoding, done) => {
console.log(object)
// ready to process the next chunk
done()
}
readable.pipe(writable)
const items = [1, 2, 3]
items.forEach(item => readable.Push(item))
// end the stream
readable.Push(null)
_
データはどこから来ていますか?ストリーミングデータソースの場合は、配列との間で変換するよりも、変換ストリームを使用してストリームを操作する方が適切です。
tl; dr;
const items = [1,2,3]
const stream = new Readable({
objectMode: true,
read() {
const item = items.pop()
if (!item) {
this.Push(null)
}
this.Push(item)
},
})
これは古い質問ですが、誰かがこれに遭遇した場合、 node-stream-array はNode.jsのはるかに単純でエレガントな実装です> = v0.10
var streamify = require('stream-array'),
os = require('os');
streamify(['1', '2', '3', os.EOL]).pipe(process.stdout);
Node 12.3以降、代わりに stream.Readable.from(iterable, [options])
を使用できます。
const { Readable } = require('stream');
const readableStream = Readable.from(arr);