2010-01-27 8 views
8

मैं पूरे दिन कई बार बार-बार सफाई कार्य करने के लिए "हार्टबीट" प्रक्रिया को लागू करने की सोच रहा हूं।सी # में लिखी गई हार्टबीट प्रक्रिया को आप कैसे बदलेंगे?

यह कमान पैटर्न का उपयोग करने के लिए एक अच्छा मौका तरह लग रहा था, तो मैं एक अंतरफलक है कि लगता है कि है:

public interface ICommand 
    { 
     void Execute(); 
     bool IsReady(); 
    } 

मैं तो कई कार्यों मैं चलाने के लिए चाहते हैं कि बना लिया है। यहाँ एक बुनियादी उदाहरण है:

class Program 
{ 
    static void Main(string[] args) 
    { 

     bool running = true; 

     Queue<ICommand> taskList = new Queue<ICommand>(); 
     taskList.Enqueue(new ProcessFilesCommand(60)); // 1 minute interval 
     taskList.Enqueue(new DeleteOrphanedFilesCommand(300)); // 5 minute interval 

     while (running) 
     { 
      ICommand currentTask = taskList.Dequeue(); 
      if (currentTask.IsReady()) 
      { 
       ThreadPool.QueueUserWorkItem(t => currentTask.Execute()); 
      } 
      taskList.Enqueue(currentTask); 
      Thread.Sleep(100); 
     } 

    } 
} 

मैं बहु सूत्रण का अधिक अनुभव नहीं है:

public class ProcessFilesCommand : ICommand 
{ 
    private int secondsDelay; 
    private DateTime? lastRunTime; 

    public ProcessFilesCommand(int secondsDelay) 
    { 
     this.secondsDelay = secondsDelay; 
    } 

    public void Execute() 
    { 
     Console.WriteLine("Processing Pending Files..."); 
     Thread.Sleep(5000); // Simulate long running task 
     lastRunTime = DateTime.Now; 
    } 

    public bool IsReady() 
    { 
     if (lastRunTime == null) return true; 

     TimeSpan timeSinceLastRun = DateTime.Now.Subtract(lastRunTime.Value); 
     return (timeSinceLastRun.TotalSeconds > secondsDelay); 
    } 

} 

अंत में, मेरे कंसोल आवेदन ThreadPool में जोड़ने के लिए कार्य इंतजार कर की तलाश में इस पाश में चलता है कुछ काम से परे मैंने ऑपरेटिंग सिस्टम क्लास में किया था। हालांकि, जहां तक ​​मैं कह सकता हूं कि मेरे किसी भी धागे किसी भी साझा राज्य तक पहुंच नहीं रहे हैं, इसलिए उन्हें ठीक होना चाहिए।

क्या यह ऐसा करने के लिए "ठीक" डिज़ाइन जैसा प्रतीत होता है? क्या आप कुछ बदलेंगे?

उत्तर

10

यह एक महान शुरुआत है। हमने हाल ही में इस तरह की चीजों का एक गुच्छा किया है, इसलिए मैं कुछ सुझाव दे सकता हूं।

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

  2. मुख्य() दिनचर्या ट्रैक करता है जब चीजें दौड़ती हैं और प्रत्येक दौड़ कितनी देर तक चलती है। प्रत्येक कमांड के बजाय "हाँ मैं तैयार हूं" या "नहीं मैं नहीं हूं" जो प्रत्येक कमांड के लिए समान होगा, केवल LastRun और अंतराल फ़ील्ड्स हैं जो मुख्य() तब निर्धारित करने के लिए उपयोग कर सकते हैं जब प्रत्येक कमांड को चलाने की आवश्यकता होती है ।

  3. एक कतार का उपयोग न करें। हालांकि यह एक कतार प्रकार के ऑपरेशन की तरह प्रतीत हो सकता है, क्योंकि प्रत्येक कमांड का अपना अंतराल होता है, यह वास्तव में एक सामान्य कतार नहीं है। इसके बजाय सभी आदेशों को एक सूची में रखें और फिर सूची को सबसे कम समय तक अगले क्रम में क्रमबद्ध करें। थ्रेड को तब तक सोएं जब तक कि चलाने के लिए पहले कमांड की आवश्यकता न हो। उस आदेश को चलाएं। चलाने के लिए अगली कमांड द्वारा सूची रिज़ॉर्ट करें। नींद। दोहराएँ।

  4. एकाधिक धागे का उपयोग न करें। यदि प्रत्येक कमांड का अंतराल एक मिनट या कुछ मिनट होता है, तो आपको शायद थ्रेड का उपयोग करने की आवश्यकता नहीं है। आप एक ही धागे पर सबकुछ करके सरल बना सकते हैं।

  5. त्रुटि प्रबंधन। इस तरह की चीज़ को यह सुनिश्चित करने के लिए व्यापक त्रुटि प्रबंधन की आवश्यकता होती है कि एक कमांड में कोई समस्या पूरे लूप को विफल न करे, और इसलिए जब आप ऐसा करते हैं तो आप किसी समस्या को डीबग कर सकते हैं। आप यह भी तय करना चाहेंगे कि क्या आदेश को तुरंत त्रुटि पर पुनः प्राप्त किया जाना चाहिए या अगली अनुसूचित दौड़ तक प्रतीक्षा करें, या यहां तक ​​कि सामान्य से अधिक देरी हो। अगर आप हर बार त्रुटि होती है तो आप कमांड में त्रुटि लॉग नहीं करना चाहेंगे (कमांड में एक त्रुटि जो अक्सर बड़ी लॉग फाइलें आसानी से बना सकती है)।

+3

# 1: मैं यह जोड़ना चाहता हूं कि आप सचमुच थ्रेड पूल थ्रेड से बाहर हो सकते हैं, जिससे आपका एप्लिकेशन मृत लॉक हो जाता है। यही कारण है कि आप अपने थ्रेडपूल में लंबे समय तक चलने वाले धागे की अनुमति नहीं देते हैं। थ्रेड पूल के लिए छोटे चलने वाले कार्यों के बारे में बिंदु के लिए –

+0

+1। –

+0

@ जोनाथन एलन, अच्छा बिंदु, मैंने इसके जवाब में इसके बारे में एक नोट जोड़ा। –

0

running चर को volatile के रूप में चिह्नित करने की आवश्यकता होगी यदि इसकी स्थिति किसी अन्य धागे द्वारा बदला जा रहा है।

उपयुक्तता के अनुसार, क्यों न केवल टाइमर का उपयोग करें?

+0

मैं टाइमर का उपयोग करने के लिए भी अधिक प्रलोभन करता हूं, और जब अगला कार्य देय होता है (जिसे आप समझने में सक्षम होना चाहिए) के लिए टाइमर सेट करें। एक सेकंड के हर 1/10 वें अपने काम की जांच करने में कोई बात नहीं। – kyoryu

+0

नहीं, ऐसा नहीं है। खराब स्थिति परिदृश्य यह है कि आप लूप के एक अतिरिक्त चक्र से गुजरते हैं। यह एक बड़ा सौदा नहीं है क्योंकि यह ध्वज फिसलने और इसे जांचने की दौड़ के कारण किसी भी तरह से हो सकता है। –

+0

@ जोनाथन एलन: अस्थिर कीवर्ड के बिना, एक रजिस्टर में चल रहा हो सकता है। –

2

मैं बीमा करने के लिए है कि आप राज्य में परिवर्तन के बारे में चिंता की जरूरत नहीं है अपने सभी कमान कक्षाएं immutable होगा।

+0

कमांड कक्षाओं में पहले से ही फ़ील्ड हैं जो बदलते हैं ताकि वे अपरिवर्तनीय नहीं हो सकें। –

+0

@ सैम हाँ, मैं सहमत हूं। लेकिन कक्षा को अपरिवर्तनीय बनाने के लिए इसे फिर से डिजाइन किया जा सकता है। – LWoodyiii

6

स्क्रैच से सबकुछ लिखने के बजाय, आप अपने आवेदन को एक ढांचे का उपयोग करके चुन सकते हैं जो आपके लिए सभी शेड्यूलिंग और थ्रेडिंग को संभालता है। ओपन-सोर्स लाइब्रेरी NCron बिल्कुल इस उद्देश्य के लिए डिज़ाइन की गई है, और इसका उपयोग करना बहुत आसान है।

इस तरह अपने काम को परिभाषित करें:

class MyFirstJob : CronJob 
{ 
    public override void Execute() 
    { 
     // Put your logic here. 
    } 
} 

और इस तरह समय-निर्धारण सेटअप सहित अपने आवेदन के लिए एक मुख्य प्रवेश बिंदु बनाने के लिए:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Bootstrap.Init(args, ServiceSetup); 
    } 

    static void ServiceSetup(SchedulingService service) 
    { 
     service.Hourly().Run<MyFirstJob>(); 
     service.Daily().Run<MySecondJob>(); 
    } 
} 

यह सभी कोड आप की आवश्यकता होगी है अगर आप इस पथ को नीचे जाने का विकल्प चुनते हैं तो लिखें। यदि आवश्यक हो तो आपको more complex schedules या dependency injection करने का विकल्प भी मिलता है, और logging को आउट ऑफ़ द बॉक्स शामिल किया गया है।

अस्वीकरण: मैं एनसीआरओएन पर मुख्य प्रोग्रामर हूं, इसलिए मैं सिर्फ एक पक्षपातपूर्ण हो सकता हूं! ;-)

+1

यह एक बहुत अच्छा सुझाव है और इसलिए एनसीआरॉन बहुत अच्छा लग रहा है! मुझे लगता है कि मैं आखिरकार इस मार्ग पर जा रहा हूं। क्या आपको लगता है कि आप दिए गए कोड पर आधार स्पर्श कर सकते हैं और लोगों के बारे में अन्य सुझाव भी बना सकते हैं? आप अनुभव की एक अद्वितीय स्थिति में हैं। रास्ते से – mmcdole

+1

+1। मुझे एनसीआरओएन के लिए परिचय देने के लिए धन्यवाद। – mmcdole

2

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

मेरी राय में इसका उपयोग करने पर विचार करें। वैसे, आपका कोड साफ़ है।

धन्यवाद।