【问题标题】:Query an Erlang process for its state?查询 Erlang 进程的状态?
【发布时间】:2010-11-19 11:14:41
【问题描述】:

Erlang 中的一个常见模式是维护状态的递归循环:

loop(State) ->
  receive
    Msg ->
      NewState = whatever(Msg),
      loop(NewState)
  end.

有没有什么方法可以通过 bif 或跟踪之类的来查询正在运行的进程的状态?由于崩溃消息说“......当状态是......”并显示崩溃进程的状态,我认为这很容易,但我很失望我无法找到执行此操作的 bif。

那么,我认为使用 dbg 模块的跟踪可以做到这一点。不幸的是,我相信因为这些循环是尾调用优化的,dbg 只会捕获对函数的第一次调用。

有什么办法吗?

【问题讨论】:

    标签: erlang


    【解决方案1】:

    看起来你是在无中生有地制造问题。 erlang:process_info/1 为调试目的提供了足够的信息。如果您真的需要循环函数参数,为什么不将其返回给调用者以响应您自己定义的特殊消息之一?

    更新: 只是为了澄清术语。在语言级别上最接近“进程状态”的是进程字典,强烈建议不要使用它。可以通过 erlang:process_info/1 或 erlang:process/2 查询。 您真正需要的是跟踪进程的本地函数调用及其参数:

    -module(ping).
    -export([start/0, send/1, loop/1]).                                                          
    
    start() ->                                                                                   
         spawn(?MODULE, loop, [0]).                                                              
    
    send(Pid) ->                                                                                 
        Pid ! {self(), ping},                                                                    
        receive                                                                                  
        pong ->                                                                                  
             pong                                                                                
        end.                                                                                     
    
    loop(S) ->                                                                                   
        receive                                                                                  
        {Pid, ping} ->                                                                           
            Pid ! pong,                                                                          
            loop(S + 1)                                                                          
        end.                                                                                    
    

    控制台:

    Erlang (BEAM) emulator version 5.6.5 [source] [smp:2] [async-threads:0] [kernel-poll:false]  
    
    Eshell V5.6.5  (abort with ^G)                                                               
    1> l(ping).                                                                                  
    {module,ping}                                                                                
    2> erlang:trace(all, true, [call]).                                                          
    23                                                                                           
    3> erlang:trace_pattern({ping, '_', '_'}, true, [local]).                                    
    5                                                                                            
    4> Pid = ping:start().                                                                       
    <0.36.0>                                                                                     
    5> ping:send(Pid).                                                                           
    pong                                                                                         
    6> flush().                                                                                  
    Shell got {trace,<0.36.0>,call,{ping,loop,[0]}}                                              
    Shell got {trace,<0.36.0>,call,{ping,loop,[1]}}                                              
    ok                                                                                           
    7>                                                                                           
    

    【讨论】:

    • 由于 erlang 拥有所有这些很酷的工具来检查和调试实时系统,我希望有一些通用的东西。你不认为知道进程的状态对调试有用吗?为什么任何语言的调试器都具有大量用于检查变量状态并与之交互的功能?
    • 太棒了。这就是我一直在寻找的。​​span>
    【解决方案2】:

    据我所知,您无法将参数传递给本地调用的函数。我希望有人能证明我错了。

    -module(loop).
    -export([start/0, loop/1]).
    start() ->
      spawn_link(fun () -> loop([]) end).
    loop(State) ->
      receive 
        Msg ->
          loop([Msg|State])
      end.
    

    如果我们想跟踪这个模块,您可以在 shell 中执行以下操作。

    dbg:tracer().
    dbg:p(new,[c]).                   
    dbg:tpl(loop, []).
    

    使用此跟踪设置,您可以查看本地调用(tpl 中的“l”表示也将跟踪本地调用,而不仅仅是全局调用)。

    5> Pid = loop:start().
    (<0.39.0>) call loop:'-start/0-fun-0-'/0
    (<0.39.0>) call loop:loop/1
    <0.39.0>
    6> Pid ! foo.
    (<0.39.0>) call loop:loop/1
    foo
    

    如您所见,只包括调用。看不到任何争论。

    我的建议是将调试和测试的正确性基于发送的消息而不是进程中保存的状态。 IE。如果您向进程发送一堆消息,请断言它做了正确的事情,而不是它具有特定的一组值。

    当然,您也可以暂时在代码中添加一些erlang:display(State) 调用。穷人调试。

    【讨论】:

    • 我想将我的任何孩子同时使用的 http 请求数(使用 ibrowse)保持在 100 以下。在这种情况下,我有一个使用计数器的节流过程。我担心计数器会与它正在计数的资源不同步,并且应用程序会变得越来越慢。所以,问题是我不能轻易测试它是否在做正确的事情。该程序将继续正常运行,只是运行速度更慢。
    【解决方案3】:

    如果你的进程使用的是OTP,那么sys:get_status(Pid)就足够了。

    您提到的错误消息由 SASL 显示。 SASL 是 OTP 中的一个错误报告守护程序。

    您在示例代码中引用的状态只是尾递归函数的参数。除了跟踪 BIF 之外,没有其他方法可以提取它。我想这在生产代码中不是一个合适的解决方案,因为跟踪仅用于调试目的

    经过行业测试的适当解决方案是在您的项目中广泛使用 OTP。然后您可以充分利用 SASL 错误报告,rb 模块来收集这些报告,sys - 检查正在运行的 OTP 兼容进程的状态,proc_lib - 使短期进程符合 OTP,等等

    【讨论】:

    • 函数是sys:get_status/1。
    • +1: sys:get_status/1 是你的朋友。我一直用这个。
    • 哈哈,好东西!我也会一直用这个。顺便说一句,gleber,我确实打算只将它用于调试,而不是用于生产系统的长期日志记录。而且,当然,我知道我提到的状态是什么。我不确定为什么这个线程中的人们一直想要澄清这一点。我使用状态的方式与乔·阿姆斯特朗 (Joe Armstrong) 在他的书中所做的方式完全相同。在 Erlang 中,除了通过递归循环对其进行线程化之外,没有其他适当的方法可以维护临时状态。事实上,我的理解是,这正是 gen_server 幕后发生的事情。
    • 事实上,请注意 OTP 使用的函数甚至是 CALLED get_state 并且您传递给它一个 Pid。这就是进程的状态。这是我问的。我不明白为什么每个地方的每一个问题都必须引发愚蠢的语义谴责。
    • @mwt:哦,来吧!还不错:)要得到正确的答案,您必须提出正确的问题,就这么简单
    【解决方案4】:
    {status,Pid,_,[_,_,_,_,[_,_,{data,[{_,State}]}]]} = sys:get_status(Pid).
    

    这就是我用来获取 gen_server 状态的方法。 (尝试将其作为评论添加到上面的回复中,但无法正确格式化。)

    【讨论】:

      【解决方案5】:

      这是一个可以在 shell 中使用的“oneliner”。

      sys:get_status(list_to_pid("<0.1012.0>")).
      

      它可以帮助您将 pid 字符串转换为 Pid。

      【讨论】:

      • 在shell中不需要使用list_to_pid,使用pid(0,1012,0)即可。
      【解决方案6】:

      事实证明,如果您使用的是 OTP,那么有比所有这些更好的答案:

      sys:get_state/1

      当时可能还不存在。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-05-24
        • 1970-01-01
        • 2012-10-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-05
        • 1970-01-01
        相关资源
        最近更新 更多