为什么节点不能处理这个正则表达式而python可以?

时间:2014-01-21 04:01:10

标签: python regex node.js

我有一个大文本文件,我正在从中提取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。

2 个答案:

答案 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