【问题标题】:Why does Elixir Plug compile plugs into AST using macro?为什么 Elixir Plug 使用宏将插件编译成 AST?
【发布时间】:2018-04-18 15:40:39
【问题描述】:

正如代码https://github.com/elixir-plug/plug/blob/v1.5.0/lib/plug/builder.ex#L183 所示,插件定义将在宏扩展阶段编译为AST。但为什么?为什么不保留plugs的定义,使用Enum.reduce_while或者递归来一一调用plugs呢?

【问题讨论】:

    标签: elixir plug


    【解决方案1】:

    我能想到的两个原因:

    1. 性能。考虑这两个做同样事情的 sn-ps,但一个使用编译函数调用,另一个使用 Enum.reduceapply

      defmodule A do
        def add1(x), do: x + 1
        def sub1(x), do: x - 1
      
        def compiled(x) do
          x
          |> add1()
          |> sub1()
          |> add1()
          |> sub1()
          |> add1()
          |> sub1()
          |> add1()
          |> sub1()
        end
      
        @pipeline [
          {A, :add1},
          {A, :sub1},
          {A, :add1},
          {A, :sub1},
          {A, :add1},
          {A, :sub1},
          {A, :add1},
          {A, :sub1}
        ]
        def runtime(x) do
          Enum.reduce(@pipeline, x, fn {module, function}, acc ->
            apply(module, function, [acc])
          end)
        end
      end
      

      一个简单的基准测试表明运行时实现慢了 5 倍。

      IO.inspect(
        :timer.tc(fn ->
          for _ <- 1..1_000_000, do: A.compiled(123)
          :ok
        end)
        |> elem(0)
      )
      
      IO.inspect(
        :timer.tc(fn ->
          for _ <- 1..1_000_000, do: A.runtime(123)
          :ok
        end)
        |> elem(0)
      )
      

      输出:

      82800
      433198
      
    2. 在编译时捕获错误。如果您将未实现 call/2 的模块传递给 plug,则会在编译时收到错误,而不是在运行时执行所有操作时通常会遇到的运行时错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-10-31
      • 1970-01-01
      • 1970-01-01
      • 2013-11-27
      • 1970-01-01
      • 2011-10-27
      • 1970-01-01
      相关资源
      最近更新 更多