gpt4 book ai didi

elixir - 为什么 Enum.concat 在连接列表时比++ 慢得多?

转载 作者:行者123 更新时间:2023-12-04 03:06:33 26 4
gpt4 key购买 nike

我尝试使用 Benchfella 进行一些快速基准测试:

defmodule ConcatListBench do
use Benchfella

@a1 Enum.to_list(1..10_000)
@a2 Enum.to_list(10_000..20_0000)

bench "++" do
@a1 ++ @a2
end

bench "Enum.concat" do
Enum.concat(@a1, @a2)
end
end

在运行它时:
$ elixir -v
Erlang/OTP 19 [erts-8.0.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Elixir 1.4.0-dev (762e7de)

$ mix bench
Settings:
duration: 1.0 s

## ConcatListBench
[10:01:09] 1/2: ++
[10:01:20] 2/2: Enum.concat

Finished in 14.03 seconds

## ConcatListBench
benchmark na iterations average time
++ 1000000000 0.01 µs/op
Enum.concat 50000 45.03 µs/op

问题是如何 Enum.concat如果 it uses 可能会更慢(超过 4k 次) ++列表内部的运算符?

我理解 Enum.concat 中的保护条款和模式匹配需要一些时间,但基准显示有很大的不同,不是吗?

更新:这是由于 Constant Folding , 使用 ++ 连接在编译时优化并需要立即运行。所以这个基准不太现实。

最佳答案

简短回答:Constant Folding .

更长的答案:当 Elixir 编译为 beam 时,Elixir 中的模块属性将替换为它们的字面值。文件。例如,下面的代码:

defmodule ConcatListBench do
@a1 Enum.to_list(1..10)
@a2 Enum.to_list(10..20)

def plusplus, do: @a1 ++ @a2

def concat, do: Enum.concat(@a1, @a2)
end

编译为:
-module('Elixir.ConcatListBench').
...
concat() ->
'Elixir.Enum':concat([1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]).

plusplus() ->
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ++
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20].

Erlang 编译器的 sys_core_fold 进行常量折叠优化的模块, evaluates ++ operations as much as possible at compile time .由于在这种情况下,两个列表都是文字,它可以完全消除函数调用并将其替换为结果列表。所以在你的基准测试中, ++函数只是返回一个已经存在于 VM 中的列表。跟做 1 + 2 一样快(这也是恒定折叠到 3 ):
...
bench "1 + 2" do
1 + 2
end
...
## ConcatListBench
benchmark na iterations average time
1 + 2 1000000000 0.01 µs/op
++ 1000000000 0.01 µs/op
Enum.concat 50000 37.89 µs/op

更现实的基准是间接调用 ++ Erlang 编译器不会折叠的:
def plus_plus(a, b), do: a ++ b

bench "++" do
plus_plus(@a1, @a2)
end

这些是 3 次运行的输出:
## ConcatListBench
benchmark na iterations average time
Enum.concat 50000 37.44 µs/op
++ 50000 41.65 µs/op

## ConcatListBench
benchmark na iterations average time
++ 50000 36.07 µs/op
Enum.concat 50000 38.58 µs/op

## ConcatListBench
benchmark na iterations average time
Enum.concat 50000 39.34 µs/op
++ 50000 40.74 µs/op

所以真的,如果您的列表在编译时不是恒定的,那么两种方式都一样快。我希望 Enum.concat稍微慢一点(特别是对于小列表),因为它比 ++ 做更多的工作.

关于elixir - 为什么 Enum.concat 在连接列表时比++ 慢得多?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39567317/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com