Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Elixir结构访问效率_Elixir - Fatal编程技术网

Elixir结构访问效率

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

我正在实现一个排序算法来对结构集合进行排序。我需要根据每个结构中特定键的值对集合进行排序。我可以将键硬编码到函数中,但我想对其进行推广。正如您在下面看到的,专用实现比通用实现快3倍

有没有比defp get_value(x,key),do:get_in(x,[Access.key(key)])更有效的方法来获取结构中的键的值?它来自于

专业化

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)