异步转换流不能并行工作吗?

时间:2019-05-17 11:33:37

标签: node.js nodejs-stream

我正在从NodeJS中的流中读取数据,然后在转换流中使用异步函数处理该数据。我希望此转换流可以并行发起对异步函数的多次调用,但似乎一次只能执行一次。

为了说明我的期望,我在下面编写了一个小程序,该程序生成从0limit - 1的数字,然后将其传递到转换流中,并以较小的延迟递增每个数字。如果您在下面运行程序,则数字1到20将被顺序记录,所有记录都有一个很小的延迟。

由于默认的highWaterMark为16,我希望它们以16 + 4的块记录。是否有可能获得我想要的行为,如果可以,怎么办?

即读取流将非常快地生成数据,但转换速度较慢,但​​应接收到最高水位,然后等待其数据已处理完毕,然后从读取流中请求更多数据。

const stream = require('stream')
const limit = 20
let index = 0

const numberStream = new stream.Readable({
  objectMode: true,
  read (amount) {
    const innerLimit = Math.min(index + amount, limit)
    while (index < innerLimit) {
      this.push(index++)
    }
    if (index === limit) {
      this.push(null)
    }
  },
})

const delayedIncStream = new stream.Transform({
  objectMode: true,
  transform (item, _, cb) {
    setTimeout(() => cb(null, item + 1), 100)
  },
})

const resultStream = numberStream.pipe(delayedIncStream)

resultStream.on('data', console.log)

2 个答案:

答案 0 :(得分:1)

您可以使用nodejs软件包parallel-transform-stream来实现这一点,同时保留转换后的数据的顺序。

您的示例随后可以按以下方式重写以并行转换所有数字:

const stream = require('stream')
const ParallelTransform = require('parallel-transform-stream').default
const limit = 20
let index = 0

const numberStream = new stream.Readable({
  objectMode: true,
  read (amount) {
    const innerLimit = Math.min(index + amount, limit)
    while (index < innerLimit) {
      this.push(index++)
    }
    if (index === limit) {
      this.push(null)
    }
  },
})

const delayedIncStream = new (ParallelTransform.create((item, _, cb) => {
  setTimeout(() => cb(null, item + 1), 100)
}))({
  objectMode: true,
  maxParallel: 20
})

const resultStream = numberStream.pipe(delayedIncStream)

resultStream.on('data', console.log)

答案 1 :(得分:0)

答案是,如本文档最后一部分所解释:https://nodejs.org/api/stream.html#stream_transform_transform_chunk_encoding_callback

  

transform._transform()永远不会并行调用;流实现队列机制,并且要接收下一个块,必须同步或异步调用回调。