【发布时间】:2020-03-05 09:20:32
【问题描述】:
对于文件中的每一行,我想执行计算密集型任务,例如图像压缩。我遇到的问题是数据输入得太快并且压倒了内存。理想情况下,我希望能够在处理数据时暂停并继续流。
我最初尝试将readline 模块与这样的文件流一起使用:
const fileStream = fs.createReadStream('long-list.txt')
const rl = readline.createInterface({ input: fileStream })
rl.on('line', (line, lineCount) => {
doTheHeavyTask(line)
})
但是,这很快就会在成千上万次调用doTheHeavyTask() 时使内存不堪重负。
我决定将每一行推入一个队列并创建一个事件,当上一行处理完毕后,将下一行出列:
const lineQ = new Queue() // From the 'queue-fifo' module
rl.on('line', (line, lineCount) => {
lineQ.enqueue(line)
})
const lineEmitter = new EventEmitter() // From the 'events' module
lineEmitter.on('processNextLine', async () => {
await doTheHeavyTask( lineQ.dequeue() )
if (!lineQ.isEmpty()) lineEmitter.emit('processNextLine')
})
setTimeout( () => lineEmitter.emit('processNextLine'), 20) // Give rl a moment to enqueue some lines
这行得通,但它似乎有点老套,并不比一次读取文件好多少。
我对 Javascript 中的“背压”和“生成器”等概念有模糊的了解,但不知道如何应用它们。
【问题讨论】:
-
doHeavyTask是异步的吗? -
@JonasWilms 是的,
doTheHeavyTask是异步的。但即使它是同步的,我相信rl将继续发出'line'事件,只要它可以在文件中读取。 -
没有。它不会。 JS 有一个可观察到的同步执行模型。不会同时运行任何代码。
标签: javascript node.js stream fs