2012-03-28 10 views
6

मेरे पास वर्तमान में एक सिंगलटन है, जिसमें आरंभ करने के लिए 10 सेकंड तक लग सकते हैं। हालांकि, मैं नहीं चाहता कि मेरे उपयोगकर्ताओं को इस प्रारंभिक के लिए दंडित (प्रतीक्षा) करना पड़े, इसलिए मैं एप्लिकेशन स्टार्टअप के दौरान पृष्ठभूमि थ्रेड पर इस घटक को बूटस्ट्रैप करना चाहता हूं। यहाँ मैं क्या है:पृष्ठभूमि पैटर्न पर एक सिंगलटन शुरू करने के लिए सामान्य पैटर्न

सिंगलटन:

public class MySingleton 
{ 
    private static MySingleton _instance; 
    private static readonly object _locker = new object(); 

    private MySingleton() 
    { 
     Init(); 
    } 
    public static MySingleton Instance 
    { 
     if(_instance == null) _instance = new MySingleton(); 
     return _instance; 
    } 
    public void Init() 
    { 
     lock(_locker) 
     { 
      if(_instance != null) return; 

      // long running code here... 
     } 
    } 
} 

आवेदन स्टार्टअप:

Task.Factory.StartNew(() => MySingleton.Instance.Init()); 

इस कोड को काम, डबल init के खिलाफ गार्ड, उपयोगकर्ता के किनारे मामले के खिलाफ गार्ड यह आवश्यकता होगी, इससे पहले कि यह करता है इनिट() को कॉल करने के लिए भूल गए किसी के खिलाफ शुरूआत और गार्ड भी किया।

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

क्या इसे संभालने के लिए कोई क्लीनर/अच्छा/बेहतर तरीका है?

हर किसी की मदद के लिए अग्रिम धन्यवाद।

** संपादित करें: टिप्पणियों में बताया गया है कि, इनिट को गलती से निजी के रूप में स्कॉप्ड किया गया था। यह सार्वजनिक होना चाहिए और इसे सही किया गया है।

+1

आप का उपयोग करना चाहिए 'लेज़ी <>' अपने सिंगलटन [के रूप में जॉन स्कीट द्वारा प्रचार] (प्रारंभ करने में http://csharpindepth.com/Articles/ सामान्य/सिंगलटन.एएसपीएक्स) प्रारंभिकरण को तब तक ऑफ़लोड करने के लिए जब तक कि सिंगलटन वास्तव में उपयोग नहीं किया जाता है। –

+1

जॉन उस लेख में कहता है "मेरी निजी प्राथमिकता समाधान 4 के लिए है:" जो आलसी समाधान नहीं है। कृपया उनके तर्क और अधिक जानकारी के लिए आलेख पढ़ें। –

+0

@ मिच व्हाट - हे, मुझे लगता है (10 बार मैंने इसे पढ़ा है) मैंने उदाहरणों के पिछले लेख को कभी नहीं पढ़ा। यह मुझे मेरी जीभ पकड़ने के लिए सिखाएगा (शायद नहीं) –

उत्तर

0

आप को परिभाषित करने और नीचे के रूप में सिंगलटन वर्ग बुलाना चाहिए ...

var instance = MySingleton.Instance; 
    while (true) 
    { 
    /// check for whether singleton initialization complete or not 
    if (MySingleton.Initialized) 
    { 
     break; 
    } 
    } 



    public class MySingleton 
     { 
      private static MySingleton _instance; 
      private static readonly object _locker = new object(); 
      public static bool Initialized { get; set; } 

      private MySingleton() 
      { 
       ThreadPool.QueueUserWorkItem(call => Init()); 
      } 

      public static MySingleton Instance 
      { 
       get 
       { 
        if (_instance == null) 
         _instance = new MySingleton(); 

        return _instance; 
       } 
      } 

      private void Init() 
      { 
       lock (_locker) 
       { 
        if (Initialized) 
         return; 
        // long running code here...   
        for (int i = 0; i < 10000; i++) 
        { 

        } 
        Initialized = true; 
       } 
      } 
     } 
9

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

public class MySingleton 
{ 
    private static MySingleton _instance; 
    private static ManualResetEvent _initEvent = new ManualResetEvent(false); 

    static MySingleton() 
    { 
     ThreadPool.QueueUserWorkItem(state => Init()); 
    } 

    public static MySingleton Instance 
    { 
     _initEvent.Wait(); 
     return _instance; 
    } 
    private static void Init() 
    { 
     _instance = new MySingleton(); 
     // long running code here... 


     _initEvent.Set(); 
    } 
} 

घटना एक बार ट्रिगर होने पर संकेतित रह जाएगी जिसका मतलब है कि इंस्टिट प्रॉपर्टी एएसएपी वापस करेगी जब इनिट विधि पूरी की जाएगी।

+0

भयानक समाधान! धन्यवाद! प्रश्नों के युगल हालांकि: ए) QueueUserWorkItem के लिए कोई कारण नहीं है और कार्य नहीं। फैक्टरी। स्टार्टन्यू()? बी) मैन्युअल रीसेट इवेंट का उपयोग करने के लिए कोई रीओसन और ऑटोरसेट नहीं है? – pdalbe01

+0

ए) नहीं, व्यक्तिगत वरीयता। बी) हां। 'AutoResetEvent' सिग्नल रीसेट करेगा और सभी कॉलर्स को अवरुद्ध करेगा जब पहला' प्रतीक्षा 'पूरा हो गया है – jgauffin

+1

थोड़ा मुद्दा: स्थैतिक कन्स्ट्रक्टर केवल पहली बार क्लास सदस्य का उपयोग किया जाता है। तो यह ऐप स्टार्टअप के दौरान Init() नहीं चलाएगा। – pdalbe01

0

मैं mybe के साथ एक Task<T> जाना चाहते हैं:

class Program 
{ 
    static void Main(string[] args) 
    { 
     MySingleton.Init(); 

     Thread.Sleep(7000); 

     Console.WriteLine("Getting instance..."); 
     var mySingleton = MySingleton.Instance; 
     Console.WriteLine("Got instance."); 
    } 

    public class MySingleton 
    { 
     private static Lazy<MySingleton> instance; 

     public static MySingleton Instance 
     { 
      get { return instance.Value; } 
     } 

     public static void Init() 
     { 
      var initTask = Task.Factory.StartNew(() => 
      { 
       for(int i = 0; i < 10; i++) 
       { 
        Thread.Sleep(1000); 
        Console.WriteLine("Doint init stuff {0}...", i); 
       } 

       return new MySingleton(); 
      }); 

      instance = new Lazy<MySingleton>(() => initTask.Result); 
     } 

     private MySingleton() { } 
    } 
} 
संबंधित मुद्दे