[elixir! #0047] 简单对比record, map, keyword

一篇旧文, 转载于我的cnblog. 使用的erlang版本为19

今天写个suan好了, 不是大蒜的suan, 是算盘的算. 有个人一直和我争, erlang里面record和map哪个更好. 我语重心长,循循善诱: "就用map啦, 多方便, record是什么鬼, 不就是tuple吗". 那人还不服: "record速度比map快多了, map辣鸡". 那我今天就来算一下, 看谁打脸.

刚接到一个神秘电话: "我大Keyword才是坠吼的", 所以 Keyword 选手临时加入.

round 1

有请三位选手出场!:

defmodule Suan.Record do
  require Record
  Record.defrecord :mr_rec, a: 0, b: 0, c: 0, d: 0
end

defmodule Suan.Bench do
  import Suan.Record
  @mr_map %{a: 0, b: 0, c: 0, d: 0}
  @mr_key [a: 0, b: 0, c: 0, d: 0]

  ...

请领导发言!(来自百度文库):
"咳咳嗯哼呃~ 六月是春潮奔涌、繁花争妍的季节,六月是释放活力,飞扬激情的时节,在这美好的时刻,2017年首届BEAM VM阳光体育运动会开幕了。在此,我谨代表 erlang/OTP 向本届运动会的开幕表示热烈的祝贺!向筹备本届运动会的全体工作人员表示衷心的感谢!...(省略1000字)"

请裁判说明比赛规则!:

  ...

  @doc """
  每次操作为数据结构里的某一项加1, a,b,c,d 各操作一次.
  重复10000 次.
  """
  def round1(who), do: (fn -> do_round1(who) end) |> :timer.tc() |> IO.inspect(label: "#{who}")

  defp do_round1(:mr_rec), do: rec_update(mr_rec(), 0)
  defp do_round1(:mr_key), do: key_update(@mr_key, 0)
  defp do_round1(:mr_map), do: map_update(@mr_map, 0)

请三位选手进入赛道, 各就各位!:

  ...

  defp rec_update(_rec, 10000), do: :ok
  defp rec_update(rec, n) do
    rec1 = rec |> update_a() |> update_b() |> update_c() |> update_d()
    rec_update(rec1, n+1)
  end
 
  defp update_a(rec=mr_rec(a: a)), do: mr_rec(rec, a: a+1)
  defp update_b(rec=mr_rec(b: b)), do: mr_rec(rec, b: b+1)
  defp update_c(rec=mr_rec(c: c)), do: mr_rec(rec, c: c+1)
  defp update_d(rec=mr_rec(d: d)), do: mr_rec(rec, d: d+1)

    
  defp map_update(_map, 10000), do: :ok
  defp map_update(map, n) do
    plus1 = fn x -> x+1 end
    map1  = map |> update_in([:a], plus1) |> update_in([:b], plus1) |> update_in([:c], plus1) |> update_in([:d], plus1)
    map_update(map1, n+1)
  end


  defp key_update(_key, 10000), do: :ok
  defp key_update(key, n) do
    kup! = fn x, i -> Keyword.update!(x, i, &(&1+1)) end
    key1 = key |> kup!.(:a) |> kup!.(:b) |> kup!.(:c) |> kup!.(:d)
    key_update(key1, n+1)
  end

end

裁判准备发令!:

defmodule Suan do
  @moduledoc """
  Documentation for Suan.
  """
  import Suan.Bench, only: [round1: 1]

  def start do
    Enum.each [:mr_rec, :mr_map, :mr_key], &round1/1
  end
end

"预备!噼里啪啦砰!":

iex(1)> Suan.start
mr_rec: {3829, :ok}
mr_map: {16166, :ok}
mr_key: {10398, :ok}
:ok
iex(2)> Suan.start
mr_rec: {4318, :ok}
mr_map: {22036, :ok}
mr_key: {15962, :ok}
:ok
iex(3)> Suan.start
mr_rec: {4348, :ok}
mr_map: {23165, :ok}
mr_key: {15461, :ok}
:ok

宣布比赛结果!:
record 遥遥领先, 获得冠军, keyword第二, 用时是record的三倍, map选手垫底, 用时约为record的四倍.

round 2

因不满比赛结果, 裁判愤而离场, round 2 取消.

你可能感兴趣的:(erlang,elixir)