2009-08-13 10 views
13

Un patrón común en Erlang es el bucle recursivo que mantiene el estado:Consulta un proceso de Erlang para su estado?

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

¿Hay alguna forma de consultar el estado de un proceso en ejecución con un bif o rastreo o algo? Dado que los mensajes de error dicen "... cuando el estado era ..." y muestran el estado del proceso estrellado, pensé que esto sería fácil, pero me decepcionó que no haya podido encontrar un bif para hacer esto.

Entonces, pensé que utilizar el rastreo del módulo dbg lo haría. Desafortunadamente, creo que debido a que estos bucles están optimizados para llamadas de cola, dbg solo capturará la primera llamada a la función.

¿Alguna solución?

Respuesta

23

Si su proceso utiliza OTP, es suficiente hacer sys:get_status(Pid).

El mensaje de error que menciona se muestra en SASL. SASL es un error que informa daemon en OTP.

El estado al que se refiere en su código de ejemplo es solo un argumento de la función recursiva de cola. No hay forma de extraerlo utilizando nada excepto para rastrear BIF. Supongo que esta no sería una solución adecuada en el código de producción, ya que el seguimiento está destinado a ser utilizado solo con fines de depuración.

La solución adecuada, y probada en la industria, haría un uso extensivo de OTP en su proyecto. A continuación, puede sacar el máximo provecho de los informes de errores SASL, rb módulo para recoger estos informes, sys - para inspeccionar el estado del proceso en ejecución OTP-compatibles, proc_lib - para que los procesos de corta duración OTP-compatible, etc.

+1

La función es sys: get_status/1. – cthulahoops

+0

+1: sys: get_status/1 es tu amigo. Uso esto todo el tiempo. –

+0

Jaja, cosas increíbles! Usaré esto todo el tiempo, también. Dicho sea de paso, gleber, intento utilizarlo solo para la depuración, no para el registro a largo plazo en un sistema de producción. Y, por supuesto, sé cuál es el estado que menciono. No estoy seguro de por qué las personas en este hilo siguen queriendo aclarar esto. Estoy usando el estado exactamente de la misma manera que, por ejemplo, lo hace Joe Armstrong en su libro. No hay otra forma adecuada de mantener el estado temporal en Erlang que enrutarlo a través de bucles recursivos. De hecho, tengo entendido que eso es precisamente lo que está sucediendo detrás de escena en gen_server, también. – mwt

4

Parece que estás solucionando el problema de la nada. erlang: process_info/1 proporciona suficiente información para la depuración. Si realmente necesita argumentos de función de bucle, ¿por qué no se los devuelve a la persona que llama en respuesta a uno de los mensajes especiales que usted mismo define?

ACTUALIZACIÓN: Solo para aclarar la terminología. Lo más parecido al "estado del proceso" en el nivel de idioma es el diccionario de proceso, cuyo uso es altamente desaconsejado. Puede ser consultado por erlang: process_info/1 o erlang: process/2. Lo que realmente necesita es rastrear las funciones locales de procesar las llamadas junto con sus argumentos:

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

Consola:

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

Dado que erlang tiene todas estas geniales instalaciones para examinar y depurar sistemas en vivo, esperaba algo general. ¿No cree que conocer el estado de un proceso es útil para la depuración? ¿Por qué los depuradores en cualquier idioma tienen muchas funciones para examinar e interactuar con estado variable? – mwt

+0

Impresionante. Esto es lo que estaba buscando. – mwt

2

Por lo que yo sé que usted no puede obtener los argumentos pasados ​​a una función llamada localmente. Me encantaría que alguien me probara mal.

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

Si queremos rastrear este módulo, haga lo siguiente en el shell.

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

uso de este ajuste se llega a ver el rastreo de llamadas locales (la 'L' en tpl significa que se pueden rastrear las llamadas locales, así, no sólo a los globales).

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 

Como ves, solo las llamadas están incluidas. Sin argumentos a la vista.

Mi recomendación es basar la corrección en la eliminación de fallas y las pruebas en los mensajes enviados en lugar de mantener el estado en los procesos. Es decir. si envía un montón de mensajes al proceso, afirme que hace lo correcto, no que tenga un cierto conjunto de valores.

Pero, por supuesto, también puede rociar algunas llamadas erlang:display(State) temporalmente en su código. Pobre hombre está depurando.

+0

Quiero mantener el número de solicitudes http (usando ibrowse) que cualquiera de mis hijos está usando simultáneamente por debajo de 100. En este caso, tengo un proceso de aceleración que utiliza un contador. Me preocupa que el contador no se sincronice con el recurso que está contando, y que la aplicación sea cada vez más lenta. Entonces, el problema es que no puedo probar fácilmente si está haciendo lo correcto. El programa seguirá funcionando bien, solo que más despacio. – mwt

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

Eso es lo que uso para obtener el estado de un gen_server. (Intenté agregarlo como un comentario a la respuesta anterior, pero no pude obtener el formato correcto).

1

Este es un "delineador" que se puede usar en el caparazón.

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

Le ayuda a convertir una cadena pid en un Pid.

+2

En el shell no necesitas usar list_to_pid, solo usa pid (0,1012,0). –

3

Resulta que hay una respuesta mejor que todos ellos, si está usando OTP:

sys:get_state/1

Probablemente no existía en el momento.

Cuestiones relacionadas