旧题目:
">node.js readline form net。Socket (process.stdin)导致错误:堆内存不足(转换net. stdin)。套接字双工到可读流)">
…我改了,因为没有人回答,这似乎是一个重要的问题在node.js生态系统。
问题是如何解决"堆内存不足"的问题从巨大的stdin逐行读取时出错?当您将标准输出转储到文件(例如:test.log)并通过fs.createReadStream('test.log')读取到'readline'接口时,没有发生错误。
看起来像进程。stdin不是这里提到的可读流:https://nodejs.org/api/process.html process_process_stdin
为了重现这个问题,我创建了两个脚本。首先是生成大量的数据(a.js文件):
// a.js
// loop in this form generates about 7.5G of data
// you can check yourself running:
// node a.js > test.log && ls -lah test.log
// will return
// -rw-r--r-- 1 sd staff 7.5G 31 Jan 22:29 test.log
for (let i = 0 ; i < 8000000 ; i += 1 ) {
console.log(`${i} ${".".repeat(1000)}n`);
}
通过bash管道使用readline (b.js文件)的脚本:
const fs = require('fs');
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin, // doesn't work
//input: fs.createReadStream('test.log'), // works
});
let s;
rl.on('line', line => {
// deliberaty commented out to demonstrate that issue
// has nothing to do beyond readline and process.stdin
// s = line.substring(0, 7);
//
// if (s === '100 ...' || s === '400 ...' || s === '7500000') {
//
// process.stdout.write(`${line}n`);
// }
});
rl.on('error', e => {
console.log('general error', e)
})
现在当你运行;
node a.js | node b.js
将导致错误:
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
但是如果你交换
const rl = readline.createInterface({
input: process.stdin,
});
const rl = readline.createInterface({
input: fs.createReadStream('test.log')
});
和运行
node a.js > test.log
node b.js
一切正常
问题实际上归结为如何转换网络。套接字到功能齐全的可读流?,如果可能的话。
<标题>编辑:基本上我的问题是,它似乎是不可能处理大量的数据从stdin作为一个流,这是自然的Unix风格的管道。因此,尽管node.js在处理流方面非常出色,但你无法编写通过unix风格的管道处理大量数据的程序。
由于这个限制,在某些情况下完全没有必要将数据转储到硬盘驱动器,只有在使用fs.createReadStream('test.log')处理之后才可以。
我认为流都是关于在飞行中处理大量数据(以及其他用例)而不将其保存在硬盘上。
标题>你总是可以把process.stdin
当作一个正常的NodeJS流,自己处理读取:
const os = require('os');
function onReadLine(line) {
// do stuff with line
console.info(line);
}
// read input and split into lines
let BUFF = '';
process.stdin.on('data', (buff) => {
const content = buff.toString('utf-8');
for (let i = 0; i < content.length; i++){
if (content[i] === os.EOL) {
onReadLine(BUFF);
BUFF = '';
} else {
BUFF += content[i];
}
}
});
// flush last line
process.stdin.on('end', () => {
if (BUFF.length > 0) {
onReadLine(BUFF);
}
});
的例子:
// unix
cat ./somefile.txt | node ./script.js
// windows
Start-Process -FilePath "node" -ArgumentList @(".script.js") -RedirectStandardInput .somefile.txt -NoNewWindow -Wait
问题不是输入数据大小,不是Node,而是数据生成器的错误设计:它没有在消费者输出流的请求下实现暂停/恢复数据生成。而不是仅仅将数据推入console.log(..)
,你应该正确地与标准输出流交互,并正确地处理来自该流的pause
和resume
信号。
fs.createReadStream()
创建的文件输入流是正确实现的,它会根据需要暂停/恢复,因此不会使代码崩溃。