elixir - Elixir 堆栈跟踪是否包含每个输入的函数?
问题描述
我正在解决Postgrex中的一个问题,这是一个 Elixir Postgres 驱动程序。
但是,我对下面的堆栈跟踪感到困惑。(为了使其可读,我只删除了 . 的冗长参数msg_recv/4
。)
16:52:54.323 [error] GenServer #PID<0.234.0> terminating
** (FunctionClauseError) no function clause matching in Postgrex.Protocol.msg_recv/4
(postgrex 0.15.5) lib/postgrex/protocol.ex:2837: Postgrex.Protocol.msg_recv(...SNIP)
(postgrex 0.15.5) lib/postgrex/protocol.ex:816: Postgrex.Protocol.bootstrap_recv/4
(postgrex 0.15.5) lib/postgrex/protocol.ex:579: Postgrex.Protocol.handshake/2
(db_connection 2.1.0) lib/db_connection/connection.ex:69: DBConnection.Connection.connect/2
(connection 1.0.4) lib/connection.ex:622: Connection.enter_connect/5
(stdlib 3.12.1) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Last message: nil
State: Postgrex.Protocol
堆栈跟踪似乎表明handshake/2
调用bootstrap_recv/4
,但没有直接调用bootstrap_recv/4
in handshake/2
。
第 579 行确实在里面handshake/2
,并且是对的调用do_handshake/2
,其中有两个自己调用的变体ssl/2
or startup/2
。
我找不到bootstrap_recv/4
在此代码路径中调用的位置。
为什么do_handshake/2
and 之一ssl/2
和startup/2
(以及任何其他后续调用导致bootstrap_recv/4
和最终msg_recv/4
)不在堆栈跟踪中?
据推测,我误解了 Elixir 堆栈跟踪。
解决方案
编辑:对于一般问题,如此详细的问题令人遗憾,但我会留下这个问题,以防有人通过调试遇到这种情况。
不,由于 Erlang VM,Elixir 中的堆栈跟踪不包含每个输入的函数。我在Elixir 论坛上的一篇文章中发现了这一点。这个GitHub issue中也提到了它。
在erlang-questions
邮件列表中,Joe Armstrong 提到 Erlang 将其称为“最后调用优化”,并给出了解释。
下面的代码用几行简单的代码来防止尾调用演示了差异。
defmodule Demo do
def first() do
second()
# Uncomment to prevent tail-call, and `first` appears in the stacktrace.
# case second() do
# _ -> {:ok, 0}
# end
end
# Elixir knows third() is still a tail-call.
def second() do
r = third()
_ = 1 + 1
# dummy() # Uncomment to prevent tail-call, and `second` appears in the stacktrace.
r
end
def third() do
IO.inspect(Process.info(self(), :current_stacktrace))
{:ok, 0}
end
defp dummy, do: nil
end
IO.inspect(Demo.first)
堆栈跟踪的结果:
{:current_stacktrace,
[
{Process, :info, 2, [file: 'lib/process.ex', line: 765]},
{Demo, :third, 0, [file: 'demo.exs', line: 21]},
{:elixir_compiler_0, :__FILE__, 1, [file: 'demo.exs', line: 30]},
{:elixir_compiler, :dispatch, 4, [file: 'src/elixir_compiler.erl', line: 75]},
{:elixir_compiler, :compile, 3, [file: 'src/elixir_compiler.erl', line: 60]},
{:elixir_lexical, :run, 3, [file: 'src/elixir_lexical.erl', line: 15]},
{:elixir_compiler, :quoted, 3, [file: 'src/elixir_compiler.erl', line: 18]}
]}
{:ok, 0}
在同一代码中调整注释行(如前所述)会导致堆栈跟踪:
{:current_stacktrace,
[
{Process, :info, 2, [file: 'lib/process.ex', line: 765]},
{Demo, :third, 0, [file: 'demo.exs', line: 20]},
{Demo, :second, 0, [file: 'demo.exs', line: 13]},
{Demo, :first, 0, [file: 'demo.exs', line: 6]},
{:elixir_compiler_0, :__FILE__, 1, [file: 'demo.exs', line: 29]},
{:elixir_compiler, :dispatch, 4, [file: 'src/elixir_compiler.erl', line: 75]},
{:elixir_compiler, :compile, 3, [file: 'src/elixir_compiler.erl', line: 60]}
]}
{:ok, 0}
推荐阅读
- javascript - 电子:未捕获的错误:找不到模块
- expert-system - 如何在 GUI jess 应用程序中显示许多问题
- php - 如何在 laravel 中对连接表进行选择查询?
- jenkins - 开始时获取 Jenkins 构建时间
- facebook - 谷歌云存储上传文件到 Facebook 附件 API
- asp.net-core - Aspnetcore.Authentication.JwtBearer 的 Logsource 是什么
- c - C标记来自标准输入的输入
- php - SOAP 文字 WSDL 请求 JDEdwards
- swift - 访问 cocoapod 持有的字体需要什么?
- amazon-web-services - 如何在 serverless.yaml 中定义排序键