3

下面是添加二进制字节的简单实现。根据 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).
4

3 回答 3

8

一个更优雅的解决方案是:

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

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

于 2012-08-07T00:47:35.477 回答
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。)

于 2012-08-06T17:19:44.080 回答
2

如果您一次处理多个值,您甚至可以比罗伯特的 解决方案更快一点:

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.
于 2012-08-09T21:09:09.950 回答