Erlang:更快速地对二进制文件中的字节进行求和

时间:2012-08-06 15:57:05

标签: erlang

下面是添加二进制字节的简单实现。根据eprof它很慢(大约占总时间的10% - 主要是因为许多人调用了binary:part/3)。

如何优化?

calc_checksum(Packet) when is_binary(Packet)->  
    calc_checksum(Packet, 0).

calc_checksum(<<>>, Acc) -> 
    Acc band 16#FFFF;

calc_checksum(Packet, Acc) when is_binary(Packet) ->        
    W = binary:decode_unsigned(binary:part(Packet, 0, 2), little),
    NextAcc = Acc + W,
    NextBytes = binary:part(Packet, byte_size(Packet), -(byte_size(Packet)-2)),
    calc_checksum(NextBytes, NextAcc).

3 个答案:

答案 0 :(得分:8)

更优雅的解决方案是:

calc_checksum(<<W:16/little,Rest/bytes>>, Acc0) ->
    Acc1 = Acc0 + W,
    calc_checksum(Rest, Acc1);
calc_checksum(<<>>, Acc) -> Acc band 16#FFFF.

如果二进制包含奇数个字节,则此代码将生成错误。使用模式匹配通常可以提供更优雅的代码。

答案 1 :(得分:2)

binary中使用模式匹配而不是调用函数似乎使我在shell中尝试的伪基准测试的速度加倍。像这样:

calc_checksum(Packet, Acc) when is_binary(Packet) ->
    <<W:16/little, NextBytes/binary>> = Packet,
    NextAcc = Acc + W,
    calc_checksum(NextBytes, NextAcc).

(我可能错了,但是如果你将NextAcc设置为(Acc + W) band 16#FFFF,你应该得到相同的结果,如果你在非常大的二进制文件上运行它,应该避免使用bignums。)

答案 2 :(得分:2)

如果你一次处理多个值,你甚至可以加快Robert's solution以上的速度:

calc_checksum(<<W1:16/little, W2:16/little, W3:16/little, W4:16/little, Rest/bytes>>, Acc)->
    calc_checksum(Rest, Acc+W1+W2+W3+W4);
calc_checksum(<<W:16/little,Rest/bytes>>, Acc) ->
    calc_checksum(Rest, Acc+W);
calc_checksum(<<>>, Acc) -> Acc band 16#FFFF.