2012-04-13 6 views
16

मेरे पास एक लाइब्रेरी है जिसका उपयोग मैं डब्ल्यूसीएफ का उपयोग करता हूं ताकि सेटिंग्स प्राप्त करने के लिए http सेवा को कॉल किया जा सके। आम तौर पर पहली कॉल ~ 100 मिलीसेकंड लेती है और बाद में कॉल केवल कुछ मिलीसेकंड लेती है। लेकिन मुझे पता चला है कि जब मैं एक नया ऐपडोमेन बनाता हूं तो उस ऐपडोमेन से पहले डब्ल्यूसीएफ कॉल को 2.5 सेकंड से अधिक समय लगता है।नए ऐपडोमेन में किए गए पहले डब्ल्यूसीएफ कनेक्शन बहुत धीमे हैं

क्या किसी के पास कोई स्पष्टीकरण या ठीक है कि क्यों एक नए ऐपडोमेन में डब्ल्यूसीएफ चैनल की पहली रचना इतनी लंबी होगी?

ये बेंचमार्क परिणाम हैं (जब 64 बिट में रिलीज में संलग्न डिबगर के बिना चल रहा है), ध्यान दें कि किस नंबर के दूसरे सेट में पहली कनेक्शन लेता है 25 गुना से अधिक लंबे समय तक

Running in initial AppDomain 
First Connection: 92.5018 ms 
Second Connection: 2.6393 ms 

Running in new AppDomain 
First Connection: 2457.8653 ms 
Second Connection: 4.2627 ms 

यह एक पूर्ण उदाहरण नहीं है लेकिन पता चलता है कि मैं इन नंबरों का उत्पादन का सबसे:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Console.WriteLine("Running in initial AppDomain"); 
     new DomainRunner().Run(); 

     Console.WriteLine(); 
     Console.WriteLine("Running in new thread and AppDomain"); 
     DomainRunner.RunInNewAppDomain("test"); 

     Console.ReadLine(); 
    } 
} 

class DomainRunner : MarshalByRefObject 
{ 
    public static void RunInNewAppDomain(string runnerName) 
    { 
     var newAppDomain = AppDomain.CreateDomain(runnerName); 
     var runnerProxy = (DomainRunner)newAppDomain.CreateInstanceAndUnwrap(typeof(DomainRunner).Assembly.FullName, typeof(DomainRunner).FullName); 

     runnerProxy.Run(); 
    } 

    public void Run() 
    { 
     AppServSettings.InitSettingLevel(SettingLevel.Production); 
     var test = string.Empty; 

     var sw = Stopwatch.StartNew(); 
     test += AppServSettings.ServiceBaseUrlBatch; 
     Console.WriteLine("First Connection: {0}", sw.Elapsed.TotalMilliseconds); 

     sw = Stopwatch.StartNew(); 
     test += AppServSettings.ServiceBaseUrlBatch; 
     Console.WriteLine("Second Connection: {0}", sw.Elapsed.TotalMilliseconds); 
    } 
} 

AppServSettings.ServiceBaseUrlBatch करने के लिए कॉल के लिए एक सेवा के लिए एक चैनल बनाने और एक ही विधि बुला रहा है। मैंने कॉल देखने के लिए वायरशर्क का उपयोग किया है और सेवा से प्रतिक्रिया प्राप्त करने के लिए केवल एक मिलीसेकंड लेता है। यह निम्न कोड के साथ चैनल बनाता है:

public static ISettingsChannel GetClient() 
{ 
    EndpointAddress address = new EndpointAddress(SETTINGS_SERVICE_URL); 

    BasicHttpBinding binding = new BasicHttpBinding 
    { 
     MaxReceivedMessageSize = 1024, 
     OpenTimeout = TimeSpan.FromSeconds(2), 
     SendTimeout = TimeSpan.FromSeconds(5), 
     ReceiveTimeout = TimeSpan.FromSeconds(5), 
     ReaderQuotas = { MaxStringContentLength = 1024}, 
     UseDefaultWebProxy = false, 
    }; 

    cf = new ChannelFactory<ISettingsChannel>(binding, address); 

    return cf.CreateChannel(); 
} 

एप्लिकेशन की रूपरेखा से यह पता चलता है कि पहले मामले में चैनल कारखाने के निर्माण और चैनल बनाकर और विधि बुला कम से कम 100 मिलीसेकेंड

में ले जाता है चैनल फैक्ट्री का निर्माण करने वाले नए ऐपडोमेन ने चैनल बनाने के लिए 763 मिलीसेकंड, 521 मिलीसेकंड, इंटरफेस पर विधि को कॉल करने के लिए 1,0 9 8 मिलीसेकंड लिया।

TestSettingsRepoInAppDomain.DomainRunner.Run() 2,660.00 TestSettingsRepoInAppDomain.AppServSettings.get_ServiceBaseUrlBatch() 2,543.47 Tps.Core.Settings.Retriever.GetSetting (स्ट्रिंग, !! 0, !! 0, !! 0) 2,542.66 टी पी एस। Core.Settings.Retriever.TryGetSetting (स्ट्रिंग, !! 0 &) 2,522.03 Tps.Core.Settings.ServiceModel.WcfHelper.GetClient() 1,371.21 Tps.Core.Settings.ServiceModel.IClientChannelExtensions.CallWithRetry (कक्षा System.ServiceModel.IClientChannel) 1,0 9 8.83

संपादित करें

.NET CLR लोडिंग ऑब्जेक्ट के साथ परफमन का उपयोग करने के बाद मैं देख सकता हूं कि जब यह दूसरा ऐपडोमेन लोड करता है तो यह प्रारंभ में प्रारंभिक रूप से स्मृति में अधिक कक्षाओं को लोड कर रहा है। पहली फ्लैट लाइन एक विराम है जिसे मैंने पहले एपडोमेन के बाद रखा था, वहां 218 वर्ग लोड हुए हैं। दूसरा ऐपडोमेन 1,944 कुल वर्गों को लोड करने का कारण बनता है।

मुझे लगता है कि यह सभी कक्षाओं को लोड करने का मानना ​​है, इसलिए अब सवाल यह है कि यह कौन सी कक्षाएं लोड हो रही है और क्यों?

enter image description here

अद्यतन

जवाब पता चला है क्योंकि तथ्य यह है कि केवल एक AppDomain देशी छवि प्रणाली DLLs का लाभ लेने के लिए सक्षम है की हो। तो दूसरे एपडोमेन में धीमी गति से इसे सभी सिस्टम को फिर से भरना पड़ा। * डब्ल्यूसीएफ द्वारा उपयोग किए जाने वाले डीएलएस। पहला एपडोमेन उन डीएलएस के पूर्व ngened देशी संस्करणों का उपयोग कर सकता है, इसलिए यह एक ही स्टार्टअप लागत नहीं थी।

LoaderOptimizationAttribute की जांच कर रही है कि Petar सुझाव दिया, कि वास्तव में इस मुद्दे को ठीक करने के लिए, पहली बार

यहाँ WCF से अधिक सामान का उपयोग करने के रूप में उतना ही समय लेने के लिए या तो MultiDomain or MultiDomainHost परिणाम दूसरा AppDomain में का उपयोग कर लग रहा था के बाद आप डिफ़ॉल्ट विकल्प देख सकते हैं, ध्यान दें कि विधानसभाओं के दूसरे AppDomain कोई भी में मूल निवासी कहते हैं, जिसका अर्थ है कि वे सभी rejitted जा करने के लिए है जो समय

enter image description here

यहाँ जोड़ने के बाद है के सभी ले रहा था था, LoaderOptimiza मुख्य रूप से टियन (लोडर ऑप्टिमाइजेशन। मल्टीडीडोमेन)। आप देख सकते हैं कि सब कुछ साझा AppDomain

enter image description here

यहां उपयोगकर्ता LoaderOptimization (LoaderOptimization.MultiDomainHost) मुख्य करने के बाद है में भरी हुई है। आप देख सकते हैं कि सभी प्रणाली DLLs साझा कर रहे हैं, लेकिन अपने ही DLLs और GAC में कोई नहीं प्रत्येक AppDomain

enter image description here

सेवा का उपयोग कर MultiDomainHost जवाब है इस सवाल के लिए कहा जाए के लिए

तो में अलग से लोड किए गए हैं, क्योंकि इसमें तेजी से स्टार्टअप समय है और मैं गतिशील रूप से निर्मित असेंबली को हटाने के लिए ऐपडोमेन को अनलोड कर सकता हूं कि सेवा

उत्तर

9

सीएलआर लोडर को कक्षाओं को लोड करने के तरीके को बताने के लिए आप अपने मुख्य को LoaderOptimization विशेषता के साथ सजाने के लिए तैयार कर सकते हैं।

[LoaderOptimization(LoaderOptimization.MultiDomain)] 
MultiDomain - Indicates that the application will probably have many domains that use the same code, and the loader must share maximal internal resources across application domains. 
+1

के लिए उस कोर के लिए अधिकतम किया गया था, धन्यवाद, जो वास्तव में नए ऐपडोमेन में पहली बार और 2 एमएमएस के लिए 35 एमएस होने का समय कम करता है दूसरा, लेकिन क्या यह दूसरी ऐपडोमेन में लोड की गई असेंबली को उतारने से रोक देगा? ऐप ऐपडोमेन का उपयोग करने का एक कारण यह है कि यह एक लंबी चल रही सेवा है जिसे एक क्रिया करने के लिए कस्टम कोड लोड करने की आवश्यकता होती है, इसलिए मुझे अभी भी कुछ असेंबली को उतारने में सक्षम होना चाहिए ताकि सेवा का आकार असंबद्ध न हो । – BrandonAGr

+1

यह सेटिंग दूसरे ऐपडोमेन से असेंबली असेंबली को रोक नहीं सकती है। –

+0

कौन सा ऐप स्क्रीन शॉट्स का उत्पादन कर रहा है? Sysinternals सामान? –

1

क्या आपके पास IE में परिभाषित HTTP प्रॉक्सी है? (शायद एक ऑटो कॉन्फ़िगर स्क्रिप्ट)। यह एक कारण हो सकता है।

अन्यथा मुझे लगता है कि यह समय है कि सभी डीएलएस लोड करने में लग रहा है। समय लेने में क्या देखने के लिए, एक्टुल कॉल से प्रॉक्सी सृजन को सेवा में डिलीट करने का प्रयास करें।

+0

मैंने पहले प्रॉक्सी सेटिंग्स की जांच की और मुझे नहीं लगता कि यह है। मुझे इसकी लोडिंग डीएलएस पर भी संदेह है क्योंकि अगर ऐसा होता तो पहला डब्ल्यूसीएफ प्रयास नए ऐपडोमेन के समान देरी क्यों नहीं देखता? एक बात मैंने नोटिस की थी कि जब यह नया ऐपडॉमेन बना रहा था, तो सीपीयू उपयोग 2.5 सेकंड – BrandonAGr

1

मुझे following article मिला जो इस बात के बारे में बात करता है कि केवल पहला ऐपडोमेन मूल छवि डीएलएस का उपयोग कैसे कर सकता है, इसलिए एक बच्चे के एपडोमेन को हमेशा जेआईटी के लिए मजबूर किया जाएगा जो शुरुआती ऐपडोमेन को नहीं है। इससे मैं देख रहा हूं कि प्रदर्शन प्रभाव का कारण बन सकता है, लेकिन क्या किसी भी तरह से यह प्रदर्शन जुर्माना नहीं मिलना संभव होगा?

यदि असेंबली के लिए कोई मूल छवि है, तो केवल पहले AppDomain मूल छवि का उपयोग कर सकते हैं। अन्य सभी ऐपडोमेन को कोड को जेआईटी-संकलित करना होगा जिसके परिणामस्वरूप एक महत्वपूर्ण CPU लागत हो सकती है।

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