2009-08-13 67 views
13

在二郎一個常見的模式是遞歸循環維持狀態:查詢Erlang進程的狀態?

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

有什麼辦法來查詢正在運行的進程的狀態與BIF或跟蹤的東西?由於崩潰消息說「......狀態是......」並顯示崩潰過程的狀態,我認爲這很容易,但我很失望,我沒有找到bif來做到這一點。

那麼,我想通過使用dbg模塊的跟蹤來做到這一點。不幸的是,我相信因爲這些循環是尾部調用優化的,所以dbg只會捕獲到函數的第一個調用。

任何解決方案?

回答

23

如果您的過程使用的是OTP,那麼做sys:get_status(Pid)就足夠了。

您提到的錯誤消息顯示爲SASL。 SASL是錯誤報告守護進程OTP

您在示例代碼中提到的狀態只是尾遞歸函數的參數。除了追蹤BIF之外,沒有辦法使用任何其他方法來提取它。我猜這在生產代碼中不是一個合適的解決方案,因爲跟蹤旨在僅用於調試目的

正確且經過業界測試的解決方案將在您的項目中廣泛使用OTP。然後,您可以充分利用SASL錯誤報告,rb模塊收集這些報告,sys - 檢查正在運行的OTP兼容過程的狀態,proc_lib - 使短暫過程符合OTP標準等。

+1

函數是sys:get_status/1。 – cthulahoops 2009-08-14 10:37:25

+0

+1:sys:get_status/1是你的朋友。我經常用這個。 – 2009-08-14 13:31:13

+0

哈哈,真棒!我也會一直使用這個。 順便提一句,我確實打算只用它進行調試,而不是用於生產系統的長期記錄。 而且,當然,我知道我說的是什麼狀態。我不確定爲什麼在這個線程中的人不斷澄清這一點。我使用的狀態與喬阿姆斯特朗在他的書中所做的完全相同。在Erlang中,除了通過遞歸循環對其進行線程化之外,沒有其他合適的方法來維護臨時狀態。事實上,我的理解是,gen_server背後的情況正是如此。 – mwt 2009-08-14 16:24:10

4

它看起來像你是無中生有的問題。 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>                       
+0

由於erlang擁有所有這些用於檢查和調試實時系統的很酷設備,所以我希望有一些通用的東西。 您不認爲知道進程的狀態對調試有用嗎?爲什麼任何語言的調試器都有很多用於檢查和與變量狀態交互的功能? – mwt 2009-08-13 22:04:18

+0

太棒了。這是我正在尋找的。 – mwt 2009-08-14 00:00:23

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 

正如你所看到的,只是調用包括在內。看不到任何爭論。

我的建議是在調試和測試發送的消息而不是狀態保存在進程中的基礎上的正確性。即如果你發送了一大堆消息,聲稱它做的是正確的事情,而不是它有一定的值。

但是,當然,你也可以在代碼中臨時調用一些erlang:display(State)調用。窮人的調試。

+0

我想保留任何我的孩子同時使用的http請求數(使用ibrowse)。在這種情況下,我有一個使用計數器的限制進程。我擔心這個計數器會與它正在計數的資源不同步,並且這個應用會變得越來越慢。所以,問題是我不能輕易測試它是否做得正確。該計劃將繼續運行良好,只是更慢。 – mwt 2009-08-13 23:39:56

2
{status,Pid,_,[_,_,_,_,[_,_,{data,[{_,State}]}]]} = sys:get_status(Pid). 

這就是我用來獲取gen_server的狀態。 (試圖添加它作爲對上述回覆的評論,但無法正確格式化。)

1

這是一個「oneliner」,可以在shell中使用。

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

它可以幫助您將pid字符串轉換爲Pid。

+2

在shell中你不需要使用list_to_pid,只需使用pid(0,1012,0)即可。 – 2012-06-23 14:00:43

3

原來還有比所有這些更好的答案,如果你使用OTP:

sys:get_state/1

也許它並沒有在當時存在。