2009-04-20 6 views
28

मेरे पास एक प्रक्रिया है जिसे हर पंद्रह सेकंड में कुछ काम करने की आवश्यकता होती है। मैं वर्तमान में इस तरह कर रहा हूँ:एरलांग में समय-समय पर कुछ करने का सबसे अच्छा तरीका क्या है?

 
    -behavior(gen_server). 

    interval_milliseconds()-> 15000. 
    init()-> 
     {ok, 
     _State = FascinatingStateData, 
     _TimeoutInterval = interval_milliseconds() 
     }. 

    %% This gets called automatically as a result of our handlers 
    %% including the optional _TimeoutInterval value in the returned 
    %% Result 
    handle_info(timeout, StateData)-> 
     {noreply, 
     _State = do_some_work(StateData), 
      _TimeoutInterval = interval_milliseconds() 
     }. 

यह काम करता है, लेकिन यह अत्यंत भंगुर है: अगर मैं अपने सर्वर नया संदेश को पढ़ाने के लिए चाहते हैं, जब मैं किसी भी नए हैंडलर समारोह लिखते हैं, मैं शामिल करने के लिए याद करने के लिए है इसके वापसी मूल्य में वैकल्पिक टाइमआउट अंतराल।

 
    %% Someone wants to know our state; tell them 
    handle_call(query_state_data, _From, StateData)-> 
     {reply, StateData, _NewStateData = whatever()}; 

आप अंदाज़ा लगा सकते हैं, मैं कर दिया है कि बहुत की एक संख्या गलती की

 
    %% Someone wants to know our state; tell them 
    handle_call(query_state_data, _From, StateData)-> 
     {reply, StateData, _NewStateData = whatever(), interval_milliseconds()}; 

बजाय: यह कहना है कि अगर मैं एक तुल्यकालिक कॉल से निपटने रहा हूँ, मैं ऐसा करने की जरूरत है, बार। यह बुरा है, क्योंकि कोड एक बार query_state_data संदेश को संभालता है, टाइमआउट अब जेनरेट नहीं होता है, और पूरा सर्वर रोक देता है। (मैं मशीन पर एक खोल प्राप्त करके मैन्युअल रूप से "डिफ्रिबिलेट" कर सकता हूं और हाथ से "टाइमआउट" संदेश भेज सकता हूं, लेकिन ... eww।)

अब, मैं हमेशा उस वैकल्पिक टाइमआउट पैरामीटर को निर्दिष्ट करने के लिए याद रखने की कोशिश कर सकता हूं मेरे परिणाम मूल्य में। लेकिन यह स्केल नहीं करता है: मैं किसी दिन भूल जाऊंगा, और एक बार फिर इस बग पर घूर रहा हूं। तो: एक बेहतर तरीका क्या है?

मुझे नहीं लगता कि मैं एक वास्तविक लूप लिखना चाहता हूं जो हमेशा के लिए चलता है, और अपना अधिकांश समय सोता है; ऐसा लगता है कि ओटीपी की भावना का सामना करना पड़ता है। send_interval/2:

उत्तर

19

सबसे अच्छा तरीका है:

init([]) -> 
    Timer = erlang:send_after(1, self(), check), 
    {ok, Timer}. 

handle_info(check, OldTimer) -> 
    erlang:cancel_timer(OldTimer), 
    do_task(), 
    Timer = erlang:send_after(1000, self(), check), 
    {noreply, Timer}. 
+1

एर्लांग को छूने के बाद से यह कुछ सालों से रहा है, लेकिन ऐसा लगता है कि मैं क्या कर रहा हूं। धन्यवाद। – offby1

7

timer मॉड्यूल :)

+0

यह नहीं सबसे अच्छा समाधान है: http://erlang.org/doc/efficiency_guide/commoncaveats.html#id60206 – mspanc

35

उपयोग timer का प्रयोग करें। उदाहरण के लिए:

-behavior(gen_server). 

interval_milliseconds()-> 15000. 
init()-> 
    timer:send_interval(interval_milliseconds(), interval), 
    {ok, FascinatingStateData}. 

%% this clause will be called every 15 seconds 
handle_info(interval, StateData)-> 
    State2 = do_some_work(StateData) 
    {noreply, State2}. 
+1

/मुझे माथे बू आती है धन्यवाद :) – offby1

+1

जब तक आपको सटीक टाइमआउट उप-मिलीसेकंड की आवश्यकता नहीं होती है और फिर आपको अपना खुद का समाधान –

+19

रोल करने की आवश्यकता है, मैंने टाइमर के बजाय erlang: send_after का उपयोग करना चुना है: send_interval, और मैंने सोचा कि यह क्यों समझाएगा कि क्यों। ऐसा इसलिए है क्योंकि मेरे हैंडल_इनो को पूरा करने में इतना समय लग सकता है कि अगली अंतराल आने पर यह अभी भी चल रहा है, और मैं नहीं चाहता कि टाइमआउट संदेश कतार में ढेर हो जाएं। Erlang का उपयोग करके: send_after (एक बार init फ़ंक्शन में, और एक बार फिर handle_info (टाइमआउट, ...) फ़ंक्शन के अंत में), मैं यह सुनिश्चित कर सकता हूं कि प्रत्येक टाइमआउट पिछले एक के बाद _at कम से कम_ अंतराल_मिलीसेकंड आता है। यह सभी के लिए सही नहीं हो सकता है, लेकिन यह मेरे लिए सही लगता है। – offby1

संबंधित मुद्दे