读取 15075 行数据时 Nodejs 栈溢出?

发布于 1周前 作者 sinazl 来自 nodejs/Nestjs

读取 15075 行数据时 Nodejs 栈溢出?
一共两万多行数据,我用二分法发现在读取 15075 行数据的时候就会报栈溢出,但是这行数据并没有什么不同。代码如下:
中间的逻辑判断部分比较复杂?大佬无视就好。主要看我的递归哪里错了?

function getdata(line)
{
i++;
if (typeof line ==‘string’){//判断是否为字符串
var dataarray = line.split(’,’);
if (person.hasOwnProperty(dataarray[4]+dataarray[7]) == false){//判断是否字符串已存在,key 为 brand+x
person[dataarray[4]+dataarray[7]] = dataarray;


k ++;
}
else{//如果已存在


if (real_length(String(dataarray)) > real_length(String(person[dataarray[4]+dataarray[7]]))){//比较字符串的非空长度,后者比前者大则替代


l++;
fWriteError.write(person[dataarray[4]+dataarray[7]]+os.EOL)//将淘汰的字符串记录下来
person[dataarray[4]+dataarray[7]] = dataarray;




}
else if(real_length(String(dataarray)) == real_length(String(person[dataarray[4]+dataarray[7]]))){//比较字符串的非空长度,如果两者相等
if (jmz.GetLength(String(dataarray[6])) > jmz.GetLength(String(person[dataarray[4]+dataarray[7]][6])) ){//比较字符串中 addr 字段的字符数
console.log(dataarray[6]);
console.log(person[dataarray[4]+dataarray[7]][6]);
person[dataarray[4]+dataarray[7]] = dataarray;
l++;
}
else{
l++
}

}
else{
l++;
}
}
}
if(i<15705)
{
getdata(dataArrayAll[i])
}
}
getdata(dataArrayAll[0]);


6 回复

不会整理代码。。各位放到格式化工具里看一下吧。。。


不懂 js,但是这个排版可以调整下,看着真难受

v8 现在应该可以自动去除尾递归的,可能是你的 node 版本太老了,不行就改成迭代好了

  1. 能用循环做的事情就不要用递归,递归相比循环有相当大的性能差距。

    2. node.js 只有特定几个版本有尾递归优化,而且需要 flag 来开启,最新版本是没有的( http://node.green/),函数调用的 Maximum call stack size 就是一个一万多的值。另外,ES6 里的尾递归优化是需要有 return 才可以的。

    2. 大文件读取尽量用 Stream,可以指定分块的长度,而且不会一直阻塞 event loop.

    3. 如果一定要用递归才能实现的逻辑,通过 setTimeout(func, 0)、setImmediate(func)、或者 process.nextTick(func) 把把递归的深度从 call stack 转移到 task queue.

    4. 另外代码优化相关的,能在循环外通过局部变量存起来的值就不用在循环里用函数调用去读取。

在处理大量数据时,Node.js 栈溢出通常是由于递归调用深度过大或单次函数调用栈帧过大导致的。对于读取 15075 行数据时出现栈溢出的情况,可以考虑以下几种解决方案:

  1. 使用非递归方法: 如果你的代码中有递归调用,尝试将其改写为迭代方法。递归调用会占用栈空间,而迭代方法则使用堆空间,可以避免栈溢出。

  2. 分批处理数据: 不要一次性读取所有 15075 行数据,而是将其分批处理。例如,每次读取 1000 行,处理完后再读取下一批。

    const fs = require('fs');
    const readline = require('readline');
    
    const fileStream = fs.createReadStream('data.txt');
    const rl = readline.createInterface({
        input: fileStream,
        crlfDelay: Infinity
    });
    
    let lineCount = 0;
    rl.on('line', (line) => {
        // 处理每行数据
        lineCount++;
        if (lineCount % 1000 === 0) {
            // 每处理1000行数据,可以进行一些操作,如保存状态或输出日志
            console.log(`Processed ${lineCount} lines`);
        }
    });
    
    rl.on('close', () => {
        console.log('File processed');
    });
    
  3. 增加栈大小: 虽然不推荐,但你可以尝试增加 Node.js 的栈大小。使用 --stack-size 标志启动 Node.js,例如 node --stack-size=8192 yourScript.js。不过,这种方法只是治标不治本,应尽量避免。

通过以上方法,可以有效避免在读取大量数据时 Node.js 栈溢出的问题。

回到顶部