2012-01-18 20 views
12

मैं विंडोज सेवा लिख ​​रहा हूं जो हर कुछ मिनटों में "कुछ" संसाधित करेगा।निष्पादन अवधि से अधिक समय लेता है जब टाइमर व्यवहार?

public Service() 
     { 
      this.InitializeComponent(); 
      this.ServiceName = Name; 
      this.CanPauseAndContinue = true; 
      this.CanShutdown = true; 

      this.eventLog.Source = Name; 

      // initialize timer 
      this.timer.Elapsed += this.TimerElapsed; 
     } 

     private void TimerElapsed(object sender, ElapsedEventArgs e) 
     { 
      eventLog.WriteEntry("Starting syncronization...", EventLogEntryType.Information); 

      if (this.processor.PrepareToRun()) 
      { 
       this.processor.Run(); 
      } 
     } 

मुझे आश्चर्य है अगर this.processor.Run() लंबे समय और अगले TimerElapsed घटना ले जाएगा क्या होगा बढ़ा दी जाएगी:

यहाँ कुछ कोड है? क्या यह छोड़ देगा? क्या यह समाप्त होने के बाद एएसएपी इंतजार करेगा और चलाएगा? क्या मुझे उन परिदृश्यों और कोडों पर विचार करना चाहिए?

मैं उपयोग कर रहा हूँ System.Timers.Timer

संपादित:

private void TimerElapsed(object sender, ElapsedEventArgs e) 
     { 
      eventLog.WriteEntry("Starting syncronization...", EventLogEntryType.Information); 

      try 
      { 
       this.timer.Stop(); 
       if (this.processor.PrepareToRun()) 
       { 
        this.processor.Run(); 
       } 
      } 
      catch (Exception ex) 
      { 
       LoggingAndNotifications.LogAndNotify(ex); 

      } 
      finally 
      { 
       this.timer.Start(); 
      } 
     } 

संपादित 2

public Service() 
     { 
      this.InitializeComponent(); 
      this.ServiceName = Name; 
      this.CanPauseAndContinue = true; 
      this.CanShutdown = true; 

      this.eventLog.Source = Name; 

      // initialize timer 
      this.timer.AutoReset = false; 
      this.timer.Elapsed += this.TimerElapsed; 
     } 

     private void TimerElapsed(object sender, ElapsedEventArgs e) 
     { 
      eventLog.WriteEntry("Starting syncronization...", EventLogEntryType.Information); 

      try 
      { 
       if (this.processor.PrepareToRun()) 
       { 
        this.processor.Run(); 
       } 
      } 
      catch (Exception ex) 
      { 
       LoggingAndNotifications.LogAndNotify(ex); 
       throw; 
      } 
      finally 
      { 
       this.timer.Start(); 
      } 
     } 

उत्तर

10

यह इसे फिर से एक और धागा पर फोन करता हूँ।

आपरेशन की प्रकृति के आधार आप चाहते हैं जाएगा करने के लिए या तो:

  1. इस पर ध्यान न दें, यदि कोड कहा जाता है कई एक साथ कॉल के लिए सुरक्षित है तो यह ठीक हो सकता है। बेशक, आपको पता है कि यह ठीक है।
  2. टाइमर-ट्रिगर ऑपरेशन पर लॉक करें। ध्यान रखें कि आप लंबित परिचालनों की कतार के साथ समाप्त हो सकते हैं, जो बहुत खराब है।
  3. टाइमर-ट्रिगर ऑपरेशन पर लॉक करें, शून्य के टाइमआउट के साथ लॉक प्राप्त करने का प्रयास करें और यदि आप असफल हो जाते हैं तो इसे छोड़ दें - आखिरी बार यहां एक धागा भी है।
  4. टाइमर को एक-ऑफ टाइमर के रूप में रखें जिसे आप प्रत्येक कॉल के अंत में पुनरारंभ करते हैं।
+0

में मेरी विशिष्ट स्थिति के लिए # 4 पसंद है। क्या मेरा संपादन (मूल पोस्ट में) सही दिखता है यदि मैं उस परिदृश्य को चाहता हूं? – katit

+4

टाइमर को रोकने में मदद नहीं मिलेगी, अगर प्रक्रिया में बहुत से सक्रिय टीपी थ्रेड हैं तो विलम्बित ईवेंट हैंडलर कॉल में देरी हो सकती है। ऑटोरसेट संपत्ति को इसके बजाय गलत पर सेट करें। –

+0

मैं बहुत सावधान रहूंगा 2. 1 या तो स्पष्ट रूप से काम करता है या नहीं, लेकिन जब आपको वास्तव में हर एक्स मिनट की आवश्यकता होती है तो यह बहुत अच्छा होता है। 3 और 4 के बीच का अंतर "कुछ छोड़े गए प्रत्येक एक्स मिनट" और "अंतिम समाप्त होने के बाद हर एक्स मिनट" के बीच होता है। दोनों की जगह है और अक्सर या तो ठीक है। आपको '.Stop() 'टाइमर की आवश्यकता नहीं है, यह आसान और सुरक्षित है (केवल कुछ मामलों में कुछ अजीब मामलों का मतलब है कि आप इसे दूर तक नहीं मिला है) ताकि इसे पहले स्थान पर ऑटो-रीसेट न किया जा सके। 'ऑटोरसेट' को गलत पर सेट करें, या सिस्टम का उपयोग करें। थ्रेडिंग। टाइमर 'टाइमआउट। अनंत' अवधि के साथ। –

3

आप देख सकते हैं कि क्या यह नमूना अनुप्रयोग के साथ क्या होगा:

class Program 
{ 
    static void Main(string[] args) 
    { 
     System.Timers.Timer timer = new System.Timers.Timer(2000); 
     timer.Elapsed += new System.Timers.ElapsedEventHandler(OnTimedObject); 
     timer.Start(); 

     while (true) 
     { 
     } 

    } 

    static void OnTimedObject(object source, ElapsedEventArgs e) 
    { 
     Console.WriteLine("entered"); 
     Thread.Sleep(3000); 
     Console.WriteLine("exited"); 

    } 
} 

आप दो देखेंगे 'में प्रवेश किया' तार 'से बाहर निकल गया' से पहले दिखाने के पहले दिखाई देता है। यह जारी रहेगा। तो धागे एक दूसरे पर कदम नहीं उठाएंगे।

(Btw, मैं अनंत छोरों की वकालत कर रहा हूँ नहीं। :))

+0

एक अनंत लूप का समर्थन नहीं करने का कोई कारण नहीं है। कुछ मामलों जहां एक जानबूझकर व्यक्ति की जगह होती है (उदाहरण के लिए विंडोज़ संदेश पंप) कुछ ऐसे मामले हैं जहां जानबूझकर लोगों के पास मामला होता है, और शेष स्पष्ट रूप से बग होते हैं और नहीं "शायद एक अच्छा विचार प्रतीत हो, तो वकील मत बनो यह "शिविर। –

2

जब टाइमर घटना उठाया है, टाइमर कोड थ्रेड पूल पर निष्पादन के लिए निर्धारित है। सबसे अधिक संभावना है कि इसे किसी अन्य धागे में निष्पादित किया जाएगा लेकिन यह विभिन्न कारकों (प्रोसेसर, थ्रेड उपयोग आदि) पर निर्भर करता है। हालांकि इसमें टाइमर के साथ कुछ भी नहीं है - यह थ्रेड पूल का कर्तव्य है।

व्यक्तिगत रूप से मैं टाइमर अंतराल का कभी भी उपयोग नहीं करता हूं। मैं टाइमर को एक बार चलाने के लिए सेटअप करता हूं और मेरे कोड को निष्पादित करने के बाद इसे फिर से सेटअप करता है। इस प्रकार मैं सुनिश्चित करता हूं कि कोड केवल एक धागे में निष्पादित किया गया हो।

private void TimerFired(object sender, System.Timers.ElapsedEventArgs e) { 
    // only execute the code within this method if we are able to 
    // get a lock. This will ensure that any Timer firings will be 
    // ignored that occur while we're already doing work (OnTimer) 
    if (Monitor.TryEnter(lockObj)) { 
     try { 
      // do work here 
     } finally { 
      Monitor.Exit(lockObj); 
     } 
    } 
} 

अन्यथा, अगर विधि एक अवधि टाइमर अंतराल से अधिक समय हो सकता था, विधि:

3

मैं निम्नलिखित अगर मैं बाद में टाइमर फायरिंग विधि निष्पादित करने के लिए फिर से पहले यह काम पूरा होने के नहीं करना चाहते का उपयोग पहले समाप्त होने से पहले एक अलग धागे पर निष्पादन शुरू करना समाप्त हो सकता है।

+0

आपके मामले में यदि विधि अवधि टाइमर अंतराल से अधिक लंबी है तो आप बहुत सारी प्रतीक्षाओं के साथ समाप्त हो जाएंगे और विधि लगातार निष्पादित की जाएगी। –

+0

@the_joric - मुझे नहीं लगता कि यह सच है। TryEnter एक अवरुद्ध विधि नहीं है, और तुरंत लौटता है, या तो सत्य या गलत लौटता है। अगर यह ताला हो जाता है, तो यह अंदर काम निष्पादित करता है। यदि ऐसा नहीं होता है, तो टाइमरफार्ड विधि बिना किसी काम के जल्दी से निकलती है। – hatchet

+0

हाँ, आप सही हैं - मेरी गलती :) –

0

मैंने इस तरह के परिदृश्यों को संभालने के लिए ऐसा किया है। ऑफ-कोर्स आपको असाधारण मामलों जैसे बहु-थ्रेडेड कार्यों के लिए इसे ट्विक करने की आवश्यकता है।

public Service() 
    { 
     bool _IsProcessRunning = false; 
     this.InitializeComponent(); 
     this.ServiceName = Name; 
     this.CanPauseAndContinue = true; 
     this.CanShutdown = true; 

     this.eventLog.Source = Name; 

     // initialize timer 
     this.timer.Elapsed += this.TimerElapsed; 
    } 

    private void TimerElapsed(object sender, ElapsedEventArgs e) 
    { 
     if(!_IsProcessRunning) 
     { 
      DoSomething(); 
     }   
    } 

    private void DoSomething() 
    { 
     try 
     { 
      _IsProcessRunning = true; 

      // Do our stuff here 
     } 
     catch(Exception Ex) 
     {    
     } 
     finally 
     { 
      _IsProcessRunning = false; 
     } 
    } 
0

निष्पादन अवधि से अधिक समय लेता है जब टाइमर व्यवहार?

जब कार्य निष्पादन समय टाइमर समय अवधि से अधिक समय लेता है। TimerElapsed घटना एक नए थ्रेड में उठाया जाएगा। यह छोड़ा नहीं जाएगा। मल्टी थ्रेडिंग System.Timers.Timer

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