Elixir结构访问效率
我正在实现一个排序算法来对结构集合进行排序。我需要根据每个结构中特定键的值对集合进行排序。我可以将键硬编码到函数中,但我想对其进行推广。正如您在下面看到的,专用实现比通用实现快3倍 有没有比defp get_value(x,key),do:get_in(x,[Access.key(key)])更有效的方法来获取结构中的键的值?它来自于 专业化Elixir结构访问效率,elixir,Elixir,我正在实现一个排序算法来对结构集合进行排序。我需要根据每个结构中特定键的值对集合进行排序。我可以将键硬编码到函数中,但我想对其进行推广。正如您在下面看到的,专用实现比通用实现快3倍 有没有比defp get_value(x,key),do:get_in(x,[Access.key(key)])更有效的方法来获取结构中的键的值?它来自于 专业化 defmodule QuickSort do def qsort([]) do [] end def qsort([pivot | r
defmodule QuickSort do
def qsort([]) do
[]
end
def qsort([pivot | rest]) do
{left, right} = Enum.partition(rest, fn(x) -> x.key < pivot.key end)
qsort(left) ++ [pivot] ++ qsort(right)
end
end
iex(74)> Benchwarmer.benchmark fn -> QuickSort.qsort(collection, :key) end
*** #Function<20.52032458/0 in :erl_eval.expr/5> ***
2.5 sec 3 iterations 863742.34 μs/op
defmodule QuickSort do
def qsort(collection, key \\ nil)
def qsort([], _) do
[]
end
def qsort([pivot | rest], key) do
{left, right} = Enum.partition(rest, fn(x) -> get_value(x, key) < get_value(pivot, key) end)
qsort(left, key) ++ [pivot] ++ qsort(right, key)
end
defp get_value(x, key), do: get_in(x, [Access.key(key)])
end
iex(79)> Benchwarmer.benchmark fn -> QuickSort.qsort(collection, :key) end
*** #Function<20.52032458/0 in :erl_eval.expr/5> ***
3.1 sec 1 iterations 3180784.0 μs/op
defmodule快速排序do
def qsort([])do
[]
结束
def qsort([pivot | rest])do
{left,right}=Enum.partition(rest,fn(x)->x.keyBenchwarmer.benchmark fn->QuickSort.qsort(collection,:key)结束
***#功能***
2.5第3节迭代863742.34μs/op
通用化
defmodule QuickSort do
def qsort([]) do
[]
end
def qsort([pivot | rest]) do
{left, right} = Enum.partition(rest, fn(x) -> x.key < pivot.key end)
qsort(left) ++ [pivot] ++ qsort(right)
end
end
iex(74)> Benchwarmer.benchmark fn -> QuickSort.qsort(collection, :key) end
*** #Function<20.52032458/0 in :erl_eval.expr/5> ***
2.5 sec 3 iterations 863742.34 μs/op
defmodule QuickSort do
def qsort(collection, key \\ nil)
def qsort([], _) do
[]
end
def qsort([pivot | rest], key) do
{left, right} = Enum.partition(rest, fn(x) -> get_value(x, key) < get_value(pivot, key) end)
qsort(left, key) ++ [pivot] ++ qsort(right, key)
end
defp get_value(x, key), do: get_in(x, [Access.key(key)])
end
iex(79)> Benchwarmer.benchmark fn -> QuickSort.qsort(collection, :key) end
*** #Function<20.52032458/0 in :erl_eval.expr/5> ***
3.1 sec 1 iterations 3180784.0 μs/op
defmodule快速排序do
def qsort(集合,键\\nil)
def qsort([],uu)do
[]
结束
def qsort([pivot | rest],key)do
{left,right}=Enum.partition(rest,fn(x)->get_value(x,key)Benchwarmer.benchmark fn->QuickSort.qsort(collection,:key)结束
***#功能***
3.1第1节迭代3180784.0μs/op
Map.get
将使您非常接近硬编码密钥,但它的速度不如Erlang对这些密钥进行额外优化的速度快。这是针对地图的两个版本。获取:
defmodule Thing do
defstruct [:key]
end
defmodule QuickSortDotKey do
def qsort([]), do: []
def qsort([pivot | rest]) do
{left, right} = Enum.partition(rest, fn(x) -> x.key < pivot.key end)
qsort(left) ++ [pivot] ++ qsort(right)
end
end
defmodule QuickSortAccessKey do
def qsort([], _), do: []
def qsort([pivot | rest], key) do
{left, right} = Enum.partition(rest, fn(x) -> get_value(x, key) < get_value(pivot, key) end)
qsort(left, key) ++ [pivot] ++ qsort(right, key)
end
defp get_value(x, key), do: get_in(x, [Access.key(key)])
end
defmodule QuickSortMapGet do
def qsort([], _), do: []
def qsort([pivot | rest], key) do
{left, right} = Enum.partition(rest, fn(x) -> Map.get(x, key) < Map.get(pivot, key) end)
qsort(left, key) ++ [pivot] ++ qsort(right, key)
end
end
defmodule Bench do
use Benchfella
bench ".key", [list: gen()] do
QuickSortDotKey.qsort(list)
end
bench "Access.key", [list: gen()] do
QuickSortAccessKey.qsort(list, :key)
end
bench "Map.get", [list: gen()] do
QuickSortMapGet.qsort(list, :key)
end
defp gen, do: for _ <- 1..10000, do: %Thing{key: :rand.uniform}
# Tests
list = for _ <- 1..10000, do: %Thing{key: :rand.uniform}
sorted = Enum.sort_by(list, &(&1.key))
true = sorted == QuickSortDotKey.qsort(list)
true = sorted == QuickSortAccessKey.qsort(list, :key)
true = sorted == QuickSortMapGet.qsort(list, :key)
end
Map.get
将使您非常接近硬编码密钥,但它的速度不如Erlang最有可能对其进行一些额外优化的硬编码密钥快。这是针对地图的两个版本。获取:
defmodule Thing do
defstruct [:key]
end
defmodule QuickSortDotKey do
def qsort([]), do: []
def qsort([pivot | rest]) do
{left, right} = Enum.partition(rest, fn(x) -> x.key < pivot.key end)
qsort(left) ++ [pivot] ++ qsort(right)
end
end
defmodule QuickSortAccessKey do
def qsort([], _), do: []
def qsort([pivot | rest], key) do
{left, right} = Enum.partition(rest, fn(x) -> get_value(x, key) < get_value(pivot, key) end)
qsort(left, key) ++ [pivot] ++ qsort(right, key)
end
defp get_value(x, key), do: get_in(x, [Access.key(key)])
end
defmodule QuickSortMapGet do
def qsort([], _), do: []
def qsort([pivot | rest], key) do
{left, right} = Enum.partition(rest, fn(x) -> Map.get(x, key) < Map.get(pivot, key) end)
qsort(left, key) ++ [pivot] ++ qsort(right, key)
end
end
defmodule Bench do
use Benchfella
bench ".key", [list: gen()] do
QuickSortDotKey.qsort(list)
end
bench "Access.key", [list: gen()] do
QuickSortAccessKey.qsort(list, :key)
end
bench "Map.get", [list: gen()] do
QuickSortMapGet.qsort(list, :key)
end
defp gen, do: for _ <- 1..10000, do: %Thing{key: :rand.uniform}
# Tests
list = for _ <- 1..10000, do: %Thing{key: :rand.uniform}
sorted = Enum.sort_by(list, &(&1.key))
true = sorted == QuickSortDotKey.qsort(list)
true = sorted == QuickSortAccessKey.qsort(list, :key)
true = sorted == QuickSortMapGet.qsort(list, :key)
end
get_in(…,[Access.key(key)])
做了很多事情,而在这个简单的例子中,大多数事情是不需要的。它用于访问嵌套结构,因此需要迭代函数数组(更不用说需要使用Access.key
创建这些函数)。毫不奇怪,速度要慢得多
Map.get
首先调用Map.fetch
,然后检查元素是否存在,如果不存在则用默认值替换。同样,一些额外的代码
根据我的观察,最接近.key
的是Map.fetch
。或者如果你想去低级的:maps.find(key,map)
(虽然与map.fetch相比没有多少优势)
.key
之所以如此高效,是因为它直接编译成BEAM字节码,而无需调用外部函数。get_in(…,[Access.key(key)])
完成了许多在这个简单示例中不需要的事情。它用于访问嵌套结构,因此需要迭代函数数组(更不用说需要使用Access.key
创建这些函数)。毫不奇怪,速度要慢得多
Map.get
首先调用Map.fetch
,然后检查元素是否存在,如果不存在则用默认值替换。同样,一些额外的代码
根据我的观察,最接近.key
的是Map.fetch
。或者如果你想去低级的:maps.find(key,map)
(虽然与map.fetch相比没有多少优势)
.key
之所以如此高效,是因为它直接编译成BEAM字节码,而不调用外部函数。那么defp get_value(x,key),do:x[key]
呢?它抛出一个错误,说我的结构没有实现访问行为
啊,它是一个结构。这应该可以工作:defp get_value(x,key),do:Map.get(x,key)
。除了一个单独的函数之外,您还可以将它放在Enum.partition
的fn:Enum.partition(rest,fn(x)->Map.get(x,key)
中。那么如何定义get\u值(x,key),do:x[key]
呢?它抛出一个错误,说我的结构没有实现访问行为
啊,这是一个结构。这应该可以工作:defp get_value(x,key),do:Map.get(x,key)
。除了一个单独的函数之外,您还可以将其放入Enum.partition
的fn:Enum.partition(rest,fn(x)->Map.get(x,key)
。