2009-08-13 10 views
13

Wspólne deseń w Erlang jest rekurencyjne pętli, który utrzymuje stan:Zapytanie o proces Erlanga dla jego stanu?

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

Czy istnieje sposób do kwerendy stanu uruchomionego procesu z BIF lub śledzenia czy coś? Ponieważ wiadomości awaryjne mówią "... kiedy stan był ..." i pokazują stan awarii, myślałem, że to będzie łatwe, ale byłem rozczarowany, że nie udało mi się znaleźć bifa, który by to zrobił.

Tak więc, pomyślałem, że skorzystanie z funkcji śledzenia w module dbg spowoduje to. Niestety, uważam, że ponieważ te pętle są zoptymalizowane pod względem wywołania ogona, dbg przechwyci tylko pierwsze wywołanie funkcji.

Jakieś rozwiązanie?

Odpowiedz

23

Jeśli twój proces używa OTP, wystarczy wykonać sys:get_status(Pid).

Podany komunikat o błędzie jest wyświetlany przez SASL. SASL jest demonem o błędzie w OTP.

Stan, do którego odnosisz się w swoim przykładowym kodzie, jest tylko argumentem funkcji rekurencyjnej ogona. Nie można go wyodrębnić za pomocą niczego oprócz śledzenia BIF-ów. Sądzę, że nie byłoby to właściwe rozwiązanie w kodzie produkcyjnym, ponieważ śledzenie jest przeznaczone wyłącznie do celów debugowania.

Właściwe i przetestowane w branży rozwiązanie mogłoby w dużym stopniu wykorzystać OTP w projekcie. Następnie można w pełni wykorzystać możliwości raportowania błędów SASL, moduł rb zebrać te raporty, sys - wglądu do stanu zgodnego z systemem OTP-procesu, proc_lib - aby procesy krótkotrwałe OTP zgodny itp

+1

Ta funkcja to sys: get_status/1. – cthulahoops

+0

+1: sys: get_status/1 jest twoim przyjacielem. Używam tego cały czas. –

+0

Haha, niesamowite rzeczy! Użyję tego cały czas. Nawiasem mówiąc, mam zamiar używać go tylko do debugowania, a nie do długoterminowego logowania do systemu produkcyjnego. I, oczywiście, wiem, o czym jest państwo, o którym wspominam. Nie jestem pewien, dlaczego ludzie w tym wątku wciąż chcą to wyjaśnić. Używam stanu w dokładnie taki sam sposób jak np. Joe Armstrong w swojej książce. Nie ma innego właściwego sposobu utrzymywania tymczasowego stanu w Erlang, niż przeciąganie go przez pętle rekursywne. W rzeczywistości rozumiem, że właśnie to dzieje się za kulisami w serwerze gen_server. – mwt

4

Wygląda na to, że robisz problem z niczego. erlang: process_info/1 daje wystarczającą ilość informacji do celów debugowania. Jeśli NAPRAWDĘ potrzebujesz argumentów funkcji pętli, dlaczego nie oddasz go dzwoniącemu w odpowiedzi na jedną ze specjalnych wiadomości, które sam zdefiniujesz?

AKTUALIZACJA: Tylko w celu wyjaśnienia terminologii. Najbardziej zbliżoną do "stanu procesu" na poziomie języka jest słownik procesów, którego stosowanie jest wysoce odradzane. Może być zapytany przez erlang: process_info/1 lub erlang: process/2. co rzeczywiście potrzebne jest prześledzić lokalne funkcje proces za połączenia wraz z ich argumentami:

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

konsoli:

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

Od kiedy erlang ma wszystkie te fajne urządzenia do badania i debugowania systemów na żywo, miałem nadzieję na coś ogólnego. Nie uważasz, że znajomość stanu procesu jest przydatna do debugowania? Dlaczego debuggery w dowolnym języku mają wiele funkcji do badania i interakcji ze zmiennym stanem? – mwt

+0

Awesome. Tego właśnie szukałem. – mwt

2

O ile wiem, nie można uzyskać argumenty przekazane do lokalnie nazwie funkcji. Chciałbym, żeby ktoś mi udowodnił, że się mylę.

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

Jeśli chcemy prześledzić ten moduł, wykonaj następujące czynności w powłoce.

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

Stosując tę ​​śledzenie ustawień można zobaczyć połączenia telefoniczne miejscowe („L” w OC oznacza, że ​​lokalne połączenia będą śledzone, a także, nie jedynymi globalne).

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 

Jak widać, połączenia są uwzględniane. Nie widać żadnych argumentów.

Moja rekomendacja to oparcie poprawności w debugowaniu i testowaniu wysłanych komunikatów, a nie stanu przechowywanego w procesach. To znaczy. jeśli wyślesz procesowi kilka wiadomości, upewnij się, że robi to, co trzeba, a nie, że ma określony zestaw wartości.

Oczywiście można również tymczasowo pokropić niektóre wywołania erlang:display(State) w kodzie. Biedny człowiek debuguje.

+0

Chcę zachować liczbę żądań http (przy użyciu ibrowse), które każde z moich dzieci używa jednocześnie do mniej niż 100. W tym przypadku mam proces dławiący, który używa licznika. Obawiam się, że licznik nie będzie zsynchronizowany z zasobem, który zlicza, a aplikacja będzie wolniej i wolniej. Problem polega na tym, że nie mogę łatwo sprawdzić, czy robi to dobrze. Program będzie działał dobrze, wolniej. – mwt

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

To jest to, czego używam, aby uzyskać stan serwera_generalnego. (Próbowałem dodać go jako komentarz do powyższej odpowiedzi, ale nie udało się poprawnie sformatować.)

1

To jest "oneliner" Który może być użyty w powłoce.

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

Pomaga przekształcić ciąg pid w Pid.

+2

W powłoce nie musisz używać list_to_pid, po prostu użyj pid (0,1012,0). –

3

Okazuje się, że jest to lepsze rozwiązanie niż wszystko to, jeśli używasz OTP:

sys:get_state/1

Prawdopodobnie nie istniała w tym czasie.