正如代码https://github.com/elixir-plug/plug/blob/v1.5.0/lib/plug/builder.ex#L183所示,插件定义将在宏扩展阶段编译为 AST。但为什么?为什么不只保留插件定义并使用Enum.reduce_while
或递归来一一调用插件?
问问题
82 次
1 回答
1
我能想到的两个原因:
表现。考虑这两个片段做同样的事情,但一个使用编译的函数调用,另一个使用
Enum.reduce
andapply
: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
在编译时捕获错误。如果将模块传递给
plug
未实现的模块call/2
,则会在编译时收到错误,而不是在运行时执行所有操作时通常会遇到的运行时错误。
于 2018-04-18T16:03:16.427 回答