I tried that last night and was surprised, so will share.
Benchmark script:
https://gist.github.com/3937666
Session:
1> t:bench().
Creating str of size 1048576.. done.
Converting to binary.. done.
Executing STR copy 30 times... done.
Executing BIN copy 30 times... done.
BIN: Mean: 139461.1, stdev: 7829.9
STR: Mean: 79089.4, stdev: 53349.0
No matter how hard I try, I cannot outperform lists.
R15B02, 32-bit Linux.
--
Motiejus Jakštys
Even this benchmark is not fair, because while STR is doing its work,
Erlang VM is allocating more and more memory from the OS. And then
binary has a sufficiently large heap in the VM to work on.
To be fair, we should run both string copy and binary copy before
doing the benchmarks, just to "warm up" the VM. Tried it, but doesn't
seem to help.
Please try with the module t compiled with the native option.
Also the answer to "why binary" is generally either "because unicode" or
"because memory", not "lol speed". But it would be good if "lol speed"
could be improved eventually.
--
Loïc Hoguin
Erlang Cowboy
Nine Nines
http://ninenines.eu
> Also the answer to "why binary" is generally either "because unicode" or
> "because memory", not "lol speed". But it would be good if "lol speed" could
> be improved eventually.
Thanks for the explanation.
FYI, with "native" and some more tricks:
BIN: Min: 124959.0, Max: 152380.0, Mean: 80449.2, stdev: 53616.5
STR: Min: 40768.0, Max: 340067.0, Mean: 137522.3, stdev: 7299.9
Was interesting, though. Interestingly standard deviation of binary is
quite high.
--
Motiejus Jakštys
case In of% end of field<<_:Pos/binary, Tkn:Len/binary, ?FIELD_BY, _/binary>> ->parse(In, Pos + Len + 1, 0, [Tkn | Line], Fun, Acc0);..._ ->% no match increase tokenparse(In, Pos, Len + 1, Line, Fun, Acc0)end;
Den 23/10/2012 14.00 skrev "Jesper Louis Andersen" <jesper.lou...@erlang-solutions.com>:
>
> There is no reason to believe binaries to be faster than lists for this benchmark. The list construction can take its cells from the process heap and since it is garbage collected, doing so is an (amortized) O(1) pointer move. The reverse takes O(N). So we are looking at N*O(1) + O(N) = O(N). The binary construction has to reallocate the binary once in a while which imposes a copy on the binary to make it larger. In the worst case, and when it is badly implemented, this is an O(N^2) operation. If it is better implemented, we can shave it down to O(N lg N) or thereabout, depending on the slack amount we want to allocate. But it does not seem as cheap as the other solution, barring constants.
The normal slack amount to use is some factor times the current length - eg. a doubling. This gives O(n) amortized cost (remember that while you do need to copy O(lg n) times, you need to copy far less than n elements each time - it sums up to <2n copyings).
So asymptotically it should be at level with lists (I'm fairly certain that BEAM is smart about this) - but the constant factor is still wanting...
my_list_to_binary([H|T], Acc) ->
my_list_to_binary(T, <<Acc/binary,H>>);
my_list_to_binary([], Acc) ->
Acc.Appending to a binary is optimized by the run-time system (which is
stated in the Efficiency Guide) with no help from the compiler. Therefore,
the run-time system has no way of knowing that the binary created in
my_list_to_binary/1 will be appended to, so it will *not* mark the empty
binary as appendable and reserve extra space in it for appending.
>
> I would think it would be allocated in my_list_to_binary/1, passed by
> reference, have an initial size of 256, be appended to without any copying,
> and only maybe be copied if the accumulation exceeded 256 bytes (the binary
> may be moved when it is extended.) Is the implication is that the initial
> blank binary <<>> is a different type of binary, say fixed-length or static,
> and that the first append operation triggers the copy of that binary into a
> newly allocated extendable binary (with initial size twice the original or
> 256 whichever is bigger)?
Yes, correct. The initial empty binary is a different type of binary. It is
a heap binary stored in the constant pool for the module, so the
"creation" of it is extremely cheap.
/Björn
--
Björn Gustavsson, Erlang/OTP, Ericsson AB