Erlang:用于处理二进制部件列表的高内存使用率

时间:2014-02-14 12:26:04

标签: performance memory erlang

我在Erlang中有大量内存使用问题。将我的问题(MapReduce框架的一部分)减少到最小,请考虑以下代码:

{match, Idx} = re:run(SomeBinary, <<"[A-Za-z0-9_]+">>,[global]),
List = [ {binary:part(SomeBinary, Pos, Len), 1}  || [{Pos, Len}] <- Idx],   
Sorted = lists:keysort(1, List),

处理15 MB二进制UTF-8编码文本,包含2672923个单词,内存使用上限为2 GB。 对于正则表达式部分为1,2 GB,对于keysort()则为800 MB。

即使有所有链接列表的东西,引用等,这怎么可能? 当我在计算后“暂停”进程时,内存使用量在几秒钟后减少到300MB。我在archlinux上运行Erlang R16B03。

PS 1:我也试过直接从regexp返回二进制文件,但内存使用情况相同,性能稍差。

PS 2:处理30 MB文件完全杀死我的内存并导致交换。

PS 3:在Rust中实现相同的逻辑,链接到PCRE lib for regexp(erlang也使用PCRE)的内存上限为200 MB

感谢。

2 个答案:

答案 0 :(得分:2)

我的朋友告诉我部分解决方案。 而不是使用正则表达式,手动标记器执行得更好:

[{X, 1} || X <- words(Bin)].

words(Bin) ->
    words_2(Bin, [], []).

words_2(<<C, Rest/binary>>, CAcc, WAcc) when
        (C >= $A) and (C =< $Z);
        (C >= $a) and (C =< $z);
        (C >= $0) and (C =< $9);
        C =:= $_ ->
    words_2(Rest, [C | CAcc], WAcc);
words_2(<<_, Rest/binary>>, [], WAcc) ->
    words_2(Rest, [], WAcc);
words_2(<<>>, [], WAcc) ->
    lists:reverse(WAcc);
words_2(Rest, CAcc, WAcc) ->
    words_2(Rest, [], [list_to_binary(lists:reverse(CAcc)) | WAcc]).

这会将正则表达式的1,2 GB内存使用量减少到可接受的值。 不幸的是,800 MB的列表:keysort(...)似乎是使用erlang的交易。

RegExps的执行速度通常比“手写”代码差。如果速度不是限制因素,RegExp有利于它的可读性和易于修改。

尽管RegExps存在一般性能问题,但本例中的高内存使用量似乎与“re”模块中Erlang / PCRE绑​​定的内部实现有关。

答案 1 :(得分:1)

一种标记可能非常快的二进制文件的方法是二进制:split / 3(尽管我还没有测试过它)。如果您使用全局选项并拆分任何非字母数字的字符,您可以在一次调用中获得单词列表:

http://www.erlang.org/doc/man/binary.html#split-3

查看示例2。

编辑:为了澄清,以下内容将在所有空格,点,逗号和括号上拆分二进制文件并对结果进行排序:

列出:排序(二进制:分割(Bin,[&lt;&lt;“”&gt;&gt;,&lt;&lt;“。”&gt;&gt;,&lt;&lt;“,”&gt;&gt;,&lt; ;&lt;“(”&gt;&gt;,&lt;&lt;“)”&gt;&gt;],[全球]))。

但是,这可能会使结果列表中出现空字符串,例如,如果一行中有多个空格。如果这是一个问题,他们可以在之后进行过滤。