2012-02-01 22 views
34

हमें हमारे बहु-थ्रेडेड एंटिटी फ्रेमवर्क संचालित एप्लिकेशन को डिज़ाइन करने में कुछ परेशानी हो रही है और कुछ मार्गदर्शन चाहते हैं। हम विभिन्न धागे पर इकाइयां बना रहे हैं, इकाइयों को संग्रह में जोड़ा जाता है जो तब विभिन्न wpf नियंत्रणों के लिए डेटा बाध्य होते हैं। ऑब्जेक्ट कॉन्टेक्स्ट क्लास थ्रेड सुरक्षित नहीं है, इसलिए इसका प्रबंधन करने के लिए हमारे पास 2 समाधान हैं:इकाई फ्रेमवर्क और मल्टी थ्रेडिंग

समाधान 1 में एक ही संदर्भ है और सावधानी से लॉकिंग का उपयोग यह सुनिश्चित करने के लिए करें कि कोई भी 2 धागे एक ही समय में इसका उपयोग न करें। यह लागू करने के लिए अपेक्षाकृत सरल होगा लेकिन आवेदन की अवधि के लिए संदर्भ जीवित रहने की आवश्यकता होगी। क्या इस तरह एक एकल संदर्भ उदाहरण खोलना बुरा विचार है?

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

प्रश्न: क्या दोनों समाधानों में से कोई भी वैध है, अगर आप इस बात से निपटने की अनुशंसा नहीं करते हैं कि हम इससे कैसे निपटें?

+2

@usr आपको बेहतर विचार मिला? – Cocowalla

+0

@ कोकोवाला ओपी को संबोधित करने वाले बड़े परिदृश्य को नहीं जानता, मैं नहीं करता हूं। उनके दोनों समाधानों से दर्दनाक कार्यान्वयन होगा जिससे मैं उन्हें चेतावनी दे रहा हूं। हो सकता है कि वह एक पूरी तरह से अलग रास्ता ले सकता है और ईएफ का उपयोग एकल-थ्रेडेड तरीके से कर सकता है (जिस तरह से इसका उपयोग किया जाना है)। – usr

+0

ध्यान देने योग्य एक और बात: जब आप अलग हो जाते हैं तो आप किसी इकाई में कोई भी परिवर्तन नहीं कर सकते हैं, क्योंकि वर्तमान में कोई संदर्भ उस परिवर्तन को ट्रैक नहीं कर रहा है। परिवर्तन सहेज नहीं होगा जब SaveChanges() को बाद में बुलाया जाता है। – JoeCool

उत्तर

23

सबसे पहले, मुझे लगता है कि आपने this article on MSDN पढ़ा है।

समाधान # 1 लगभग निश्चित रूप से थ्रेडिंग परिप्रेक्ष्य से सबसे सुरक्षित है, क्योंकि आप गारंटी दे रहे हैं कि केवल एक धागा किसी भी समय संदर्भ के साथ बातचीत कर रहा है। संदर्भ को ध्यान में रखते हुए स्वाभाविक रूप से गलत कुछ भी नहीं है- यह दृश्यों के पीछे डेटाबेस कनेक्शन को नहीं रख रहा है, इसलिए यह सिर्फ स्मृति ओवरहेड है। यह निश्चित रूप से, एक प्रदर्शन समस्या पेश कर सकता है यदि आप उस धागे पर बाधा डालते हैं और पूरा आवेदन सिंगल-डीबी-थ्रेड धारणाओं के साथ लिखा जाता है।

समाधान # 2 मेरे लिए अनावश्यक लगता है- आप पूरे एप्लिकेशन में सूक्ष्म बग के साथ समाप्त हो जाएंगे जहां लोग फिर से संलग्न (या अलग) इकाइयों को भूलना भूल जाते हैं।

एक समाधान एप्लिकेशन की यूआई परत में अपनी इकाई वस्तुओं का उपयोग नहीं करना है। मैं वैसे भी इसकी अनुशंसा करता हूं- संभावना है कि इकाई ऑब्जेक्ट्स की संरचना/लेआउट इष्टतम नहीं है कि आप अपने यूजर इंटरफेस पर चीजों को कैसे प्रदर्शित करना चाहते हैं (यह MVC पैटर्न के परिवार का कारण है)। आपके डीएएल में ऐसे विधियां होनी चाहिए जो व्यावसायिक तर्क विशिष्ट हैं (UpdateCustomer उदाहरण के लिए), और यह आंतरिक रूप से तय करना चाहिए कि कोई नया संदर्भ बनाना है या संग्रहीत एक का उपयोग करना है। आप एक संग्रहीत संदर्भ दृष्टिकोण से शुरू कर सकते हैं, और फिर यदि आप बाधाओं के मुद्दों में भाग लेते हैं तो आपके पास सीमित सतह क्षेत्र है जहां आपको परिवर्तन करने की आवश्यकता है।

नकारात्मकता यह है कि आपको बहुत अधिक कोड लिखने की आवश्यकता है- आपके पास ईएफ इकाइयां होंगी, लेकिन आपके पास ऐसी व्यावसायिक संस्थाएं भी होंगी जिनमें डुप्लिकेट गुण हों और ईएफ इकाइयों की संभावित रूप से भिन्नता हो। इसे कम करने के लिए, आप ईएफ इकाइयों से व्यापार संस्थाओं में प्रतिलिपि बनाने और फिर से वापस करने के लिए AutoMapper जैसे ढांचे का उपयोग कर सकते हैं।

+0

क्रिस से दूर रहें, उत्तर के लिए धन्यवाद, यह हमारे विचारों को स्पष्ट करने में बहुत मददगार था। हम आपकी सिफारिश के साथ जाने जा रहे हैं, मुझे लगता है कि हम सब कुछ करने के लिए हमारी इकाई वस्तुओं का उपयोग करने की कोशिश करने के साथ थोड़ा सा दूर ले गए थे। – MartinR

+2

समाधान 1 के साथ एक और मुद्दा कैशिंग है: संदर्भ इकाइयों को कैश करेगा, इसलिए एप्लिकेशन – Cocowalla

+0

के चल रहे इंस्टेंस के बाहर संशोधित होने पर डेटा बेकार हो जाएगा। आपके द्वारा प्रदान किया गया लिंक मेरे लिए कितना प्रकाश डाला है, यह कैसे ईएफ काम करता है। बहुत बहुत धन्यवाद। – Brandon

0

आप नहीं करते- एक लंबे समय तक रहने वाले संदर्भ चाहते हैं। आदर्श रूप से वे एक अनुरोध/डेटा ऑपरेशन के जीवन के लिए होना चाहिए।

जब इसी तरह की समस्याओं से निपटने, मैं एक भंडार है कि किसी भी प्रकार के लिए पी संस्थाओं कैश्ड को लागू करने को बंद कर, और अनुमति के लिए एक 'LoadFromDetached' जो डेटाबेस में इकाई का पता लगाएं होता है, और 'प्रतिलिपि' सभी अदिश गुण पी को छोड़कर नई संलग्न इकाई के लिए।

प्रदर्शन में थोड़ा हिट लगेगी, लेकिन यह सुनिश्चित करने के लिए बुलेट प्रूफ तरीका प्रदान करता है कि नेविगेशन गुण उनके बारे में 'भूल' से उलझन में नहीं आते हैं।

+0

मैंने हाल ही में एक समान प्रकार की समस्या में उछाल लिया है और नीचे प्रदर्शन किया है जो प्रदर्शन में काफी सुधार हुआ है। गलत जगह में टाइप किया गया, मेरा जवाब देखें – Otake

0

प्रश्न पूछने के बाद से कुछ समय हो गया है, लेकिन मैंने हाल ही में एक समान प्रकार की समस्या में उछाल लिया है और नीचे ऐसा करने के लिए समाप्त किया है जो हमें प्रदर्शन मानदंडों को पूरा करने में मदद करता है।

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

स्नैपशॉट अलगाव के लिए आपके डेटाबेस को सक्षम करने की आवश्यकता है एक बात यह है कि; अन्यथा आप deadlocks के साथ खत्म हो सकता है। आपको यह तय करने की आवश्यकता होगी कि यह आपके द्वारा किए जा रहे संचालन और संबंधित व्यावसायिक प्रक्रिया के लिए ठीक है या नहीं। हमारे मामले में यह उत्पाद इकाई पर एक साधारण अद्यतन था।

आपको शायद सबसे अच्छा हिस्सा आकार तय करने के लिए कुछ परीक्षण करने की आवश्यकता होगी और समांतरता को सीमित भी करें ताकि ऑपरेशन को पूरा करने के लिए हमेशा संसाधन हो।

private void PersistProductChangesInParallel(List<Product> products, 
     Action<Product, string> productOperationFunc, 
     string updatedBy) 
    { 
     var productsInChunks = products.ChunkBy(20); 

     Parallel.ForEach(
      productsInChunks, 
      new ParallelOptions { MaxDegreeOfParallelism = 20 }, 
      productsChunk => 
       { 
        try 
        { 
         using (var transactionScope = new TransactionScope(
           TransactionScopeOption.Required, 
           new TransactionOptions { IsolationLevel = IsolationLevel.Snapshot })) 
         { 
          var dbContext = dbContextFactory.CreatedbContext(); 
          foreach (var Product in productsChunk) 
          { 
           dbContext.products.Attach(Product); 
           productOperationFunc(Product, updatedBy); 
          } 
          dbContext.SaveChanges(); 
          transactionScope.Complete(); 
         } 
        } 
        catch (Exception e) 
        { 
         Log.Error(e); 
         throw new ApplicationException("Some products might not be updated", e); 
        } 
       }); 
    } 
7

मैं एफई और बहु ​​सूत्रण के विषय में stackoverflow धागे की एक दर्जन से अधिक लग रहे है। उनमें से सभी के पास जवाब हैं जो गहराई में समस्या को बताते हैं लेकिन वास्तव में आपको यह दिखाने के लिए नहीं दिखाते हैं कि इसे कैसे ठीक किया जाए।

ईएफ धागा सुरक्षित नहीं है, हम सब अब तक जानते हैं। लेकिन मेरे अनुभव में केवल एक ही जोखिम संदर्भ रचनाओं/जोड़-विमर्श है। वास्तव में इसके लिए एक बहुत ही सरल फिक्स है जहां आप अपनी आलसी लोडिंग रख सकते हैं।

मान लें कि आपके पास एक WPF ऐप और एक एमवीसी वेबसाइट है। जहां डब्ल्यूपीएफ ऐप मल्टीह्रेडिंग का उपयोग करता है। आप बस multithreading में डीबी संदर्भ का निपटान करते हैं और जब नहीं रखते हैं। एक एमवीसी वेबसाइट का उदाहरण दें, दृश्य प्रस्तुत किए जाने के बाद संदर्भ स्वचालित रूप से निपटान होगा।

WPF अनुप्रयोग परत में आप इस का उपयोग करें:

ProductBLL productBLL = new ProductBLL(true); 

MVC अनुप्रयोग परत में आप इस का उपयोग करें:

ProductBLL productBLL = new ProductBLL(); 

कैसे अपने उत्पाद व्यापार तर्क परत की तरह दिखना चाहिए :

public class ProductBLL : IProductBLL 
{ 
    private ProductDAO productDAO; //Your DB layer 

    public ProductBLL(): this(false) 
    { 

    } 
    public ProductBLL(bool multiThreaded) 
    { 
     productDAO = new ProductDAO(multiThreaded); 
    } 
    public IEnumerable<Product> GetAll() 
    { 
     return productDAO.GetAll(); 
    } 
    public Product GetById(int id) 
    { 
     return productDAO.GetById(id); 
    } 
    public Product Create(Product entity) 
    { 
     return productDAO.Create(entity); 
    } 
    //etc... 
} 

कैसे अपने डेटाबेस तर्क परत दिखना चाहिए:

public class ProductDAO : IProductDAO 
{ 
    private YOURDBCONTEXT db = new YOURDBCONTEXT(); 
    private bool _MultiThreaded = false; 

    public ProductDAO(bool multiThreaded) 
    { 
     _MultiThreaded = multiThreaded; 
    } 
    public IEnumerable<Product> GetAll() 
    { 
     if (_MultiThreaded) 
     { 
      using (YOURDBCONTEXT db = new YOURDBCONTEXT()) 
      { 
       return db.Product.ToList(); //USE .Include() For extra stuff 
      } 
     } 
     else 
     { 
      return db.Product.ToList(); 
     }     
    } 

    public Product GetById(int id) 
    { 
     if (_MultiThreaded) 
     { 
      using (YOURDBCONTEXT db = new YOURDBCONTEXT()) 
      { 
       return db.Product.SingleOrDefault(x => x.ID == id); //USE .Include() For extra stuff 
      } 
     } 
     else 
     { 
      return db.Product.SingleOrDefault(x => x.ID == id); 
     }   
    } 

    public Product Create(Product entity) 
    { 
     if (_MultiThreaded) 
     { 
      using (YOURDBCONTEXT db = new YOURDBCONTEXT()) 
      { 
       db.Product.Add(entity); 
       db.SaveChanges(); 
       return entity; 
      } 
     } 
     else 
     { 
      db.Product.Add(entity); 
      db.SaveChanges(); 
      return entity; 
     } 
    } 

    //etc... 
} 
0

मैं सिर्फ एक परियोजना जहां एफई उपयोग करने के लिए बहु सूत्रण के साथ की वजह से त्रुटियों की कोशिश कर रहा था।

मैं

using (var context = new entFLP(entity_connection))    
{ 
    context.Product.Add(entity); 
    context.SaveChanges(); 
    return entity; 
} 

की कोशिश की, लेकिन यह सिर्फ कई धागा त्रुटि के DataReader त्रुटि से त्रुटि का प्रकार बदल दिया है।

सरल उपाय एफई समारोह आयात

using (var context = new entFLP(entity_connection)) 
{ 
    context.fi_ProductAdd(params etc); 
} 

कुंजी डेटा के स्रोत के पास जाकर डाटा मॉडल से बचने के लिए है के साथ संग्रहित प्रक्रियाओं का इस्तेमाल किया गया।

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