[erlang-questions] Updating Myths of Erlang Performance

Loïc Hoguin essen@REDACTED
Sat Jun 4 20:57:04 CEST 2016


On 06/04/2016 02:10 PM, Valentin Micic wrote:
> On 04 Jun 2016, at 12:52 PM, Loïc Hoguin wrote:
>
>> On the other hand, if your input is a binary, converting + looping
>> might be slower than just looping through the binary. Not to mention
>> the extra garbage created.
>>
>> This section should point this out, otherwise we'll end up with users
>> converting binaries to list "because lists are faster for this".
>>
>> Also I think there are too few cases where lists win, especially in
>> that kind of comparison. You are basically comparing
>> binaries-as-string vs strings, and when using those it's frequent to
>> match against <<"abcdef", T/binary>> forms (vs [$a, $b, $c, $d, $e,
>> $f|T]) and as you pointed out, in that case binaries win.
>>
>> IMO the myth is that list strings are efficient at all when in fact
>> parsing them or even just having them in memory is inefficient. They
>> have their use cases (Unicode related mostly).
>>
>> Of course if the section is about people storing lists of integers in
>> a binary then it makes perfect sense, but I haven't seen that one yet. :-)
>>
>> --
>> Loïc Hoguin
>> http://ninenines.eu
>> Author of The Erlanger Playbook,
>> A book about software development using Erlang
>
> Consider the following functional equivalents *(A)* and *(B)*:
>
> *(A)*
> twist_tripod( <<>>, <<>>, <<>>, <<Result/binary>> )  -> Result;
> twist_tripod( <<A0:1, A1:1, A2:1, A3:1, A4:1, A5:1, A6:1, A7:1,
> RemA/binary>>,
>                <<B0:1, B1:1, B2:1, B3:1, B4:1, B5:1, B6:1, B7:1,
> RemB/binary>>,
>                <<C0:1, C1:1, C2:1, C3:1, C4:1, C5:1, C6:1, C7:1,
> RemC/binary>>,
>                <<Result/binary>> )
> ->
>      twist_tripod( RemA, RemB, RemC, <<A0:1, B0:1, C0:1,
>                                        A1:1, B1:1, C1:1,
>                                        A2:1, B2:1, C2:1,
>                                        A3:1, B3:1, C3:1,
>                                        A4:1, B4:1, C4:1,
>                                        A5:1, B5:1, C5:1,
>                                        A6:1, B6:1, C6:1,
>                                        A7:1, B7:1, C7:1, Result/binary>> )
> .
>
> *(B)*
> twist_tripod( [], [], [], Result )             -> Result;
> twist_tripod( [A|LA], [B|LB], [C|LC], Result )
> ->
>      Out_0 =     (A band 16#80)              bor     % a7
>                  ((B band 16#80) bsr 1)      bor     % b7
>                  ((C band 16#80) bsr 2)      bor     % c7
>                  ((A band 16#40) bsr 2)      bor     % a6
>                  ((B band 16#40) bsr 3)      bor     % b6
>                  ((C band 16#40) bsr 4)      bor     % c6
>                  ((A band 16#20) bsr 4)      bor     % a5
>                  ((B band 16#20) bsr 5),             % b5
>      Out_1 =     ((C band 16#20) bsl 2)      bor     % c5
>                  ((A band 16#10) bsl 2)      bor     % a4
>                  ((B band 16#10) bsl 1)      bor     % b4
>                  (C band 16#10)              bor     % c4
>                  (A band 16#08)              bor     % a3
>                  ((B band 16#08) bsr 1)      bor     % b3
>                  ((C band 16#08) bsr 2)      bor     % c3
>                  ((A band 16#04) bsr 2),             % a2
>
>      Out_2 =     ((B band 16#04) bsl 5)      bor     % b2
>                  ((C band 16#04) bsl 4)      bor     % c2
>                  ((A band 16#02) bsl 4)      bor     % a1
>                  ((B band 16#02) bsl 3)      bor     % b1
>                  ((C band 16#02) bsl 2)      bor     % c1
>                  ((A band 16#01) bsl 2)      bor     % a0
>                  ((B band 16#01) bsl 1)      bor     % b0
>                  (C band 16#01),                     % c0
>
> twist_tripod( LA, LB, LC, [Out_0, Out_1, Out_2|Result] )
> .
>
> Believe me when I tell you that *(B)* is considerably faster than *(A)
> -- *I know, as I had to write *(B)* in order to optimize *(A)*.
> However, if you look at *(A)*, it seems so much easier to see what is
> being done. Not so with *(B)*.

In this particular case I would be willing to bet that it's not so much 
because of lists, but because you are using band/bsr/bor. These make 
everything go faster. In turn, there's less variables, less garbage 
created and so on. If you rewrote your list function with binaries, you 
would probably get a large boost too.

Of course in this particular case you also fall into the parameters 
Bjorn pointed out and lists would ultimately win (plus, no binary 
matching optimization here). But that difference is probably minor 
compared to the rest of the changes.

-- 
Loïc Hoguin
http://ninenines.eu
Author of The Erlanger Playbook,
A book about software development using Erlang



More information about the erlang-questions mailing list