我有一个大文本文件,我正在从中提取URL。如果我跑:
import re
with open ('file.in', 'r') as fh:
for match in re.findall(r'http://matchthis\.com', fh.read()):
print match
它在大约一个用户时间运行并获取我想要的URL,但如果我运行其中任何一个:
var regex = /http:\/\/matchthis\.com/g;
fs.readFile('file.in', 'ascii', function(err, data) {
while(match = regex.exec(data))
console.log(match);
});
OR
fs.readFile('file.in', 'ascii', function(err, data) {
var matches = data.match(/http:\/\/matchthis\.com/g);
for (var i = 0; i < matches.length; ++i) {
console.log(matches[i]);
}
});
我明白了:
FATAL ERROR: CALL_AND_RETRY_0 Allocation failed - process out of memory
node.js
正则表达式引擎发生了什么?有什么方法可以修改它们在node
中工作的东西吗?
编辑:错误似乎是fs
为中心,因为这也会产生错误:
fs.readFile('file.in', 'ascii', function(err, data) {
});
file.in
约为800MB。
答案 0 :(得分:2)
您应该使用流文件界面逐行处理文件。像这样:
var fs = require('fs');
var byline = require('byline');
var input = fs.createReadStream('tmp.txt');
var lines = input.pipe(byline.createStream());
lines.on('readable', function(){
var line = lines.read().toString('ascii');
var matches = line.match(/http:\/\/matchthis\.com/g);
for (var i = 0; i < matches.length; ++i) {
console.log(matches[i]);
}
});
在这个例子中,我使用byline
模块将流分割成行,这样你就不会因为.read()
调用获取部分行数而错过匹配。
详细说明,你正在做的是分配~800MB的RAM作为缓冲区(在V8的堆之外),然后将其转换为ASCII字符串(从而将其转移到V8的堆中),这将至少需要800MB并且可能更多取决于V8的内部优化。我相信V8将字符串存储为UCS2或UTF16,这意味着每个字符将为2个字节(给定ASCII输入),因此您的字符串实际上大约为1600MB。
节点的最大分配堆空间为1.4GB,因此尝试创建这么大的字符串会导致V8抛出异常。
Python没有这个问题,因为它没有最大堆大小并且会咀嚼你的所有RAM。正如其他人所指出的那样,你也应该避免使用Python中的fh.read()
,因为它会将所有文件数据作为字符串复制到RAM中,而不是逐行将它与迭代器一起流式传输。
答案 1 :(得分:1)
鉴于两个程序都试图将整个1400000文件读入内存,我建议Node和Python处理大字符串的方式不同。尝试逐行搜索,问题就会消失。
例如,在Python中你可以这样做:
import re
with open ('file.in', 'r') as file:
for line in file:
for match in re.findall(r'http://matchthis\.com', line):
print match