2008-12-24 19 views
50

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

मैं का उपयोग करना चाहिए

Thread thread = new Thread(() => { 
    Thread.Sleep(millisecond); 
    action(); 
}); 
thread.IsBackground = true; 
thread.Start(); 

या

Timer timer = new Timer(o => action(), null, millisecond, -1); 

मैं का उपयोग कर Thread.Sleep बुरा डिजाइन है के बारे में कुछ articles पढ़ा था। लेकिन मैं वास्तव में समझ में नहीं आता क्यों।

लेकिन टाइमर का उपयोग करने के लिए, टाइमर ने विधि का निपटान किया है। चूंकि निष्पादन में देरी हो रही है, मुझे नहीं पता कि टाइमर का निपटान कैसे करें। क्या तुम्हारे पास कोई सुझाव है?

या यदि आपके पास देरी निष्पादन के लिए वैकल्पिक कोड भी सराहना करते हैं।

उत्तर

39

एक अंतर यह है कि सिस्टम। थ्रेडिंग। टिमर हर बार एक नया धागा बनाने के बजाय थ्रेड पूल थ्रेड पर कॉलबैक भेजता है। यदि आपको अपने आवेदन के जीवन के दौरान एक से अधिक बार होने की आवश्यकता है, तो यह धागे का एक गुच्छा बनाने और नष्ट करने के ऊपरी हिस्से को बचाएगा (एक प्रक्रिया जो बहुत संसाधन गहन है, जैसा कि आप संदर्भित करते हैं लेख के रूप में), क्योंकि यह होगा बस पूल में धागे का पुन: उपयोग करें, और यदि आपके पास एक से अधिक टाइमर एक बार चलते हैं तो इसका मतलब है कि आपके पास कम से कम थ्रेड चलेंगे (काफी संसाधनों को भी बचाएंगे)।

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

टाइमर को नष्ट करने के लिए, कॉलबैक पैरामीटर स्वीकार कर सकता है, इसलिए आप टाइमर को पैरामीटर के रूप में पास कर सकते हैं और कॉलबैक में कॉल का निपटान कर सकते हैं (हालांकि मैंने यह कोशिश नहीं की है - मुझे लगता है कि यह है संभव है कि कॉलर के दौरान टाइमर लॉक हो सकता है)।

संपादित करें: नहीं, मुझे लगता है कि आप ऐसा नहीं कर सकते हैं, क्योंकि आपको टाइमर कन्स्ट्रक्टर में कॉलबैक पैरामीटर निर्दिष्ट करना होगा।

शायद ऐसा कुछ हो सकता है? (फिर से, वास्तव में यह कोशिश की है नहीं)

class TimerState 
{ 
    public Timer Timer; 
} 

... और टाइमर शुरू करने के लिए:

TimerState state = new TimerState(); 

lock (state) 
{ 
    state.Timer = new Timer((callbackState) => { 
     action(); 
     lock (callbackState) { callbackState.Timer.Dispose(); } 
     }, state, millisecond, -1); 
} 

ताला टाइमर टाइमर से पहले मुक्त करने की कोशिश कर से टाइमर कॉलबैक रोकने चाहिए क्षेत्र सेट किया गया है।


परिशिष्ट: के रूप में टिप्पणीकार ने कहा, यदि कार्रवाई() यूआई के साथ कुछ करता है, तो एक System.Windows.Forms.Timer का उपयोग कर शायद एक बेहतर शर्त, है, क्योंकि यह यूआई पर कॉलबैक चलेंगे धागा। हालांकि, अगर यह मामला नहीं है, और यह थ्रेड पर है। नींद बनाम थ्रेडिंग। टिमर, थ्रेडिंग। टिमर जाने का रास्ता है।

+4

यह System.Windows.Forms.Timer के साथ अंतर को इंगित करने के लायक भी है, जो मैं * विश्वास करता हूं * यूआई थ्रेड पर एक फ़ंक्शन कॉल करता है, जो WinForms ऐप्स के लिए वास्तव में महत्वपूर्ण है! –

+2

भावी पाठकों के लिए, 'स्लीप' घटना कम से कम होने की गारंटी नहीं है, यह दस्तावेज है कि यह कम हो सकता है। –

+4

जिज्ञासा से बाहर ... यह कहां दस्तावेज है? –

13

मुझे लगता है थ्रेड। अगर आप वास्तव में निर्दिष्ट समय के लिए आवेदन को रोकना चाहते हैं तो नींद ठीक है। मुझे लगता है कि लोग कहते हैं कि यह एक खराब डिजाइन है क्योंकि ज्यादातर स्थितियों में लोग वास्तव में एप्लिकेशन को रोकना नहीं चाहते हैं।

उदाहरण के लिए, मैं एक पॉप 3 क्लाइंट पर काम कर रहा था जहां प्रोग्रामर थ्रेड स्लीप (1000) का उपयोग कर रहा था, जबकि सॉकेट ने मेल पुनर्प्राप्त किया था। उस स्थिति में सॉकेट के लिए एक ईवेंट हैंडलर को सॉकेट और सॉकेट पूरा होने के बाद लगातार प्रोग्राम निष्पादन को बेहतर बनाना बेहतर था।

+2

पोस्ट में न तो उदाहरण के अलावा आवेदन वास्तव में रोक रहा है। पोस्टर थ्रेड को कॉल नहीं करते, एक अलग धागे पर रोक रहा है। सीधे सो जाओ। कॉलिंग थ्रेड। सीधे सो जाओ, हाँ, बुरा विचार। –

1

सिस्टम के साथ मेरे पास एकमात्र गोमांस है। टाइमर यह है कि मैंने ज्यादातर बार मतदान सेवाओं में लंबी देरी (घंटों, मिनट) के लिए उपयोग किया है और डेवलपर्स अक्सर को लॉन्च करना भूल जाते हैं से पहले वे शुरू करते हैं टाइमर इसका मतलब है कि अगर मैं ऐप या सेवा शुरू करता हूं, तो मुझे वास्तव में निष्पादित होने से पहले टाइमर समाप्त हो जाता है (घंटे, मिनट)।

निश्चित रूप से, यह टाइमर के साथ कोई समस्या नहीं है, लेकिन मुझे लगता है कि इसका अक्सर दुरुपयोग किया जाता है क्योंकि इसका दुरुपयोग करना बहुत आसान है।

16

उपयोग ThreadPool.RegisterWaitForSingleObject बजाय टाइमर:

//Wait 5 seconds then print out to console. 
//You can replace AutoResetEvent with a Semaphore or EventWaitHandle if you want to execute the command on those events and/or the timeout 
System.Threading.ThreadPool.RegisterWaitForSingleObject(new AutoResetEvent(false), (state, bTimeout) => Console.WriteLine(state), "This is my state variable", TimeSpan.FromSeconds(5), true); 
+0

स्वीकृत उत्तर पढ़ें। टाइमर पहले से ही थ्रेड पूल का उपयोग करता है। –

+13

मैं तर्क के लिए RegisterWaitForSingleObject पसंद करता हूं ... विधि चालू होने पर विधि को निष्पादित किया जाता है ... इसलिए नौकरी पूरी होने के बाद आपको टाइमर को रोकने के लिए चाल नहीं करना चाहिए जो अच्छा नहीं है ... तो रजिस्टर WaitForSingleObject प्राकृतिक रूप से वह वही करता है जो वह चाहता है, टाइमर टाइमर बेहतर होता है जब आप विशिष्ट अंतराल पर कई बार कार्य निष्पादित करना चाहते हैं .... –

+0

मैंने एक उदाहरण जोड़ा। इस प्रश्न पर अधिक जानकारी उपलब्ध है http://stackoverflow.com/questions/1535262/net-timeouts-waitforsingleobject-vs-timer –

0

@miniscalope कोई टाइमर के बजाय ThreadPool.RegisterWaitForSingleObject का उपयोग नहीं करते, System.Threading.Timer एक कॉलबैक कतार होगा एक धागा पूल धागे पर निष्पादित करने के लिए जब समय बीत चुका है और प्रतीक्षा प्रतीक्षा की आवश्यकता नहीं है, एक वस्तु के लिए प्रतीक्षा करें थ्रेडपूल थ्रेड को सिग्नल करने के लिए इंतजार कर रहा है या थ्रेड कॉल कॉलबैक कॉल करने से पहले समाप्त होने का समय समाप्त हो जाएगा।

+0

क्या आपके पास इस पर कुछ दस्तावेज हैं? क्या आप अनिवार्य रूप से 'ThreadPool.RegisterWaitForSingleObject'' थ्रेड की तरह काम करते हैं। स्लीपबीबी बताते हैं: * "एकल ऑब्जेक्ट के लिए प्रतीक्षा करें थ्रेडपूल थ्रेड को सिग्नल करने के लिए इंतजार कर रहा है या थ्रेड कॉल कॉलबैक कॉल करने से पहले समाप्त होने का समय समाप्त हो जाएगा" *? – atconway

+0

यह थ्रेड का उपयोग नहीं करता है। सो जाओ ... स्रोत के माध्यम से खुदाई करने के बाद इसका तात्पर्य है कि यह मूल रजिस्टरवेटफोरिंगिंग ऑब्जेक्ट को कॉल करता है (मेरा कहना है कि इसका मतलब यह है कि जिस विधि को वह कॉल करता है वह बाहरी है लेकिन आंतरिक रनटाइम कॉल के रूप में सजाया जाता है ...) यदि वह धारणा है सही है, आप मान सकते हैं ([डॉक्स] से (http://msdn.microsoft.com/en-us/library/windows/desktop/ms685061 (v = vs.85) .aspx)) कि यह एक का उपयोग करेगा ऑब्जेक्ट को सिग्नल करने के लिए प्रतीक्षा करने के लिए मूल थ्रेडपूल से थ्रेड का इंतजार करें, फिर कार्यकर्ता थ्रेड पर कॉलबैक निष्पादित करें। – Matt

2

मुझे एरिक के समान समाधान को लागू करना याद है। हालांकि यह एक कामकाजी है;)

class OneTimer 
    { 
     // Created by Roy Feintuch 2009 
     // Basically we wrap a timer object in order to send itself as a context in order to dispose it after the cb invocation finished. This solves the problem of timer being GCed because going out of context 
     public static void DoOneTime(ThreadStart cb, TimeSpan dueTime) 
     { 
      var td = new TimerDisposer(); 
      var timer = new Timer(myTdToKill => 
      { 
       try 
       { 
        cb(); 
       } 
       catch (Exception ex) 
       { 
        Trace.WriteLine(string.Format("[DoOneTime] Error occured while invoking delegate. {0}", ex), "[OneTimer]"); 
       } 
       finally 
       { 
        ((TimerDisposer)myTdToKill).InternalTimer.Dispose(); 
       } 
      }, 
         td, dueTime, TimeSpan.FromMilliseconds(-1)); 

      td.InternalTimer = timer; 
     } 
    } 

    class TimerDisposer 
    { 
     public Timer InternalTimer { get; set; } 
    } 
संबंधित मुद्दे