2009-08-13 3 views
13

Ein gemeinsames Muster in Erlang ist die rekursive Schleife, den Zustand hält:Frage einen Erlang-Prozess nach seinem Zustand ab?

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

Gibt es eine Möglichkeit, den Zustand eines laufenden Prozess mit einem bif oder Verfolgung oder etwas zu fragen? Da Absturzmeldungen sagen "... wenn Zustand war ..." und den Status des abgestürzten Prozesses anzeigen, dachte ich, dies wäre einfach, aber ich war enttäuscht, dass ich keine Bif finden konnte, um dies zu tun.

Also, dann dachte ich, die Verwendung der Trace des dbg-Moduls würde es tun. Leider glaube ich, da diese Schleifen für den Endanruf optimiert sind, erfasst dbg nur den ersten Aufruf der Funktion.

Irgendeine Lösung?

Antwort

23

Wenn Ihr Prozess OTP verwendet, genügt es, sys:get_status(Pid) zu tun.

Die von Ihnen angegebene Fehlermeldung wird von SASL angezeigt. SASL ist ein Fehlerbericht Daemon in OTP.

Der Zustand, den Sie in Ihrem Beispielcode beziehen, ist nur ein Argument der Tail rekursive Funktion. Es gibt keine Möglichkeit, es zu extrahieren, mit Ausnahme von BIFs. Ich denke, das wäre keine korrekte Lösung im Produktionscode, da Tracing nur für Debug-Zwecke verwendet werden soll.

Die richtige und in der Industrie getestete Lösung wäre die umfassende Nutzung von OTP in Ihrem Projekt. Dann können Sie alle Vorteile von SASL Fehlerberichterstattung nehmen, rb Modul, diese Berichte zu sammeln, sys - den Zustand des laufenden OTP-kompatibelen Prozesses zu untersuchen, proc_lib - kurzlebige Prozesse OTP-konform zu machen, usw.

+1

Die Funktion ist sys: get_status/1. – cthulahoops

+0

+1: sys: get_status/1 ist dein Freund. Ich benutze das die ganze Zeit. –

+0

Haha, tolle Sachen! Ich werde es auch die ganze Zeit benutzen. übrigens, gleber, ich beabsichtige, es nur für das Debuggen zu verwenden, nicht für die langfristige Protokollierung auf einem Produktionssystem. Und natürlich weiß ich, was der Staat ist, dass ich erwähne. Ich bin mir nicht sicher, warum die Leute in diesem Thread dies immer wieder klären wollen. Ich verwende den Zustand genau so, wie es beispielsweise Joe Armstrong in seinem Buch tut. Es gibt keine andere Möglichkeit, den temporären Zustand in Erlang beizubehalten, als ihn durch rekursive Schleifen einzufädeln. Mein Verständnis ist, dass genau das hinter den Kulissen von gen_server vor sich geht. – mwt

4

Es sieht aus wie Sie das Problem aus dem Nichts machen. erlang: process_info/1 gibt genügend Informationen zum Debuggen. Wenn Sie WIRKLICH Schleifenfunktionsargumente benötigen, warum geben Sie sie nicht als Reaktion auf eine der speziellen Nachrichten, die Sie selbst definieren, an den Aufrufer zurück?

UPDATE: Nur um die Terminologie zu klären. Der "Zustand des Prozesses" auf Sprachenebene ist dem Prozesswörterbuch am nächsten, von dessen Verwendung dringend abgeraten wird. Er kann von erlang abgefragt werden: process_info/1 oder erlang: process/2. Was Sie wirklich brauchen, ist Prozess der lokalen Funktionen mit ihren Argumenten ruft zusammen zu verfolgen:

-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.                      

Console:

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

Da Erlang all diese coolen Möglichkeiten zum Untersuchen und Debuggen von Live-Systemen bietet, habe ich auf etwas Allgemeines gehofft. Sie denken nicht, dass Sie den Status eines Prozesses für das Debuggen nützlich sind? Warum haben Debugger in einer beliebigen Sprache viele Funktionen zur Untersuchung und Interaktion mit Variablen? – mwt

+0

Ehrfürchtig. Das ist, was ich gesucht habe. – mwt

2

Soweit ich weiß, man kann die Argumente auf eine lokal aufgerufene Funktion übergeben bekommen. Ich würde gerne jemanden haben, der mir Unrecht beweist.

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

Wenn wir dieses Modul verfolgen möchten, tun Sie Folgendes in der Shell.

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

diese Verfolgung Mit Einstellung Ortsgespräche zu sehen bekommen (das ‚l‘ in tpl bedeutet, dass Ortsgespräche als auch verfolgt werden, nicht nur global ist).

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 

Wie Sie sehen, sind nur die Anrufe enthalten. Keine Argumente in Sicht.

Meine Empfehlung ist es, die Korrektheit beim Debuggen und Testen auf die gesendeten Nachrichten und nicht auf den in Prozessen gespeicherten Status zu stützen. I.e. Wenn Sie dem Prozess eine Reihe von Nachrichten senden, erklären Sie, dass es das Richtige tut, nicht, dass es eine bestimmte Menge von Werten hat.

Aber natürlich könnten Sie auch einige erlang:display(State) Anrufe in Ihrem Code vorübergehend streuen. Das Debugging des armen Mannes.

+0

Ich möchte die Anzahl der HTTP-Anfragen (unter Verwendung von ibrowse), die alle meine Kinder gleichzeitig unter 100 verwenden. In diesem Fall habe ich einen Drosselungsprozess, der einen Zähler verwendet. Ich mache mir Sorgen, dass der Zähler mit der Ressource, die er zählt, nicht mehr synchron ist und dass die App immer langsamer wird. Das Problem ist also, dass ich nicht einfach testen kann, ob es das Richtige tut. Das Programm wird weiterhin gut laufen, nur langsamer. – mwt

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

Das ist, was ich verwende, um den Status eines gen_server zu erhalten. (Versucht, es als Kommentar zu der Antwort oben hinzuzufügen, konnte aber nicht richtig formatieren.)

1

Dies ist ein "oneliner", der in der Shell verwendet werden kann.

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

Es hilft Ihnen, eine PID-Zeichenfolge in eine PID zu konvertieren.

+2

In der Shell müssen Sie nicht list_to_pid verwenden, verwenden Sie einfach pid (0,1012,0). –

3

Es stellt sich heraus, es gibt eine bessere Antwort als alle diese, wenn Sie OTP verwenden:

sys:get_state/1

Wahrscheinlich hat es nicht an der Zeit existieren.