2012-01-06 8 views
11

मैं वर्तमान में बड़े पैमाने पर असीमित अनुप्रयोग पर काम कर रहा हूं जो पूरे टीएपी का उपयोग करता है। Task एस के लिए विधियों के हर तरीके में TaskScheduler भी इंजेक्शन दिया गया है। यह हमें कार्यों की स्पष्ट शेड्यूलिंग करने की अनुमति देता है, जैसा कि मैं समझता हूं, माइक्रोसॉफ्ट एसिंक सीटीपी के साथ नहीं जा रहा है।Async सीटीपी - कार्य शेड्यूलिंग के लिए अनुशंसित दृष्टिकोण

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

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

प्रश्न 1: क्या कोई मुझे आश्वस्त कर सकता है कि अंतर्निहित दृष्टिकोण एक अच्छा विचार है? मुझे कॉन्फ़िगरएवाइट (झूठी) और लीगेसी/थर्ड पार्टी कोड में स्पष्ट शेड्यूलिंग द्वारा कई मुद्दों को पेश किया जा रहा है। मैं कैसे सुनिश्चित कर सकता हूं कि मेरा 'प्रतीक्षा-कोड' कोड यूआई थ्रेड पर हमेशा चल रहा है, उदाहरण के लिए?

प्रश्न 2: तो, यह सोचते हैं कि हम अपने कोड से सभी TaskScheduler डि हटाने और निहित निर्धारण का उपयोग करने के लिए शुरू, हम कैसे तो डिफ़ॉल्ट कार्य अनुसूचक सेट करूँ? किसी विधि के माध्यम से शेड्यूलर मिडवे को बदलने के बारे में क्या, एक महंगी विधि का इंतजार करने से पहले, और उसके बाद इसे फिर से वापस सेट करना?

(पश्चलेख मैं पहले से ही http://msmvps.com/blogs/jon_skeet/archive/2010/11/02/configuring-waiting.aspx पढ़ा है)

उत्तर

10

मैं जवाब देने में एक शॉट ले लेंगे। ;)

प्रश्न 1: क्या कोई मुझे आश्वस्त कर सकता है कि अंतर्निहित दृष्टिकोण एक अच्छा विचार है? मुझे कॉन्फ़िगरएवाइट (झूठी) और लीगेसी/थर्ड पार्टी कोड में स्पष्ट शेड्यूलिंग द्वारा कई मुद्दों को पेश किया जा रहा है। मैं कैसे सुनिश्चित कर सकता हूं कि मेरा 'प्रतीक्षा-कोड' कोड यूआई थ्रेड पर हमेशा चल रहा है, उदाहरण के लिए?

ConfigureAwait(false) के लिए नियम बहुत सरल हैं: इसका इस्तेमाल करता है, तो अपने विधि के बाकी ThreadPool पर चलाया जा सकता है, और यह उदाहरण के लिए उपयोग नहीं करते हैं, तो आपके विधि के बाकी किसी दिए गए संदर्भ में चलाना चाहिए (, यूआई संदर्भ)।

आम तौर पर, ConfigureAwait(false) लाइब्रेरी कोड द्वारा उपयोग किया जाना चाहिए, न कि यूआई-लेयर कोड (यूआई-प्रकार परतों सहित एमवीवीएम में व्यूमोडल्स सहित)। यदि विधि आंशिक रूप से पृष्ठभूमि-गणना और आंशिक रूप से यूआई-अपडेट है, तो इसे दो तरीकों से विभाजित किया जाना चाहिए।

प्रश्न 2: तो, मान लें कि हम अपने कोड से सभी टास्कशेड्यूलर DI को हटाते हैं और निहित शेड्यूलिंग का उपयोग करना शुरू करते हैं, फिर हम डिफ़ॉल्ट कार्य शेड्यूलर कैसे सेट करते हैं?

async/await सामान्य रूप से TaskScheduler उपयोग नहीं करता है; वे एक "शेड्यूलिंग संदर्भ" अवधारणा का उपयोग करते हैं। यह वास्तव में SynchronizationContext.Current है, और TaskScheduler.Current पर वापस आता है यदि कोई SynchronizationContext नहीं है। इसलिए अपने स्वयं के शेड्यूलर को प्रतिस्थापित करना SynchronizationContext.SetSynchronizationContext का उपयोग करके किया जा सकता है। आप this MSDN article on the subject में SynchronizationContext के बारे में अधिक पढ़ सकते हैं।

डिफ़ॉल्ट शेड्यूलिंग संदर्भ आपको लगभग हर समय की आवश्यकता होनी चाहिए, जिसका अर्थ है कि आपको इसके साथ गड़बड़ करने की आवश्यकता नहीं है। यूनिट परीक्षण करते समय, या कंसोल प्रोग्राम/Win32 सेवाओं के लिए मैं इसे केवल बदलता हूं।

किसी विधि के माध्यम से शेड्यूलर मिडवे को बदलने के बारे में क्या, एक महंगी विधि का इंतजार करने से पहले, और उसके बाद इसे फिर से वापस सेट करना?

आप (संभवतः ThreadPool पर) एक महंगी आपरेशन करने के लिए चाहते हैं, तो awaitTaskEx.Run का परिणाम है।

यदि आप अन्य कारणों (जैसे, समवर्ती) के लिए शेड्यूलर बदलना चाहते हैं, तो awaitTaskFactory.StartNew का परिणाम।

इन दोनों मामलों में, विधि (या प्रतिनिधि) अन्य शेड्यूलर पर चलाया जाता है, और फिर शेष विधि इसके नियमित संदर्भ में फिर से शुरू होती है।

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

यहाँ मेरी से कुछ बिंदुओं बात मैं अपने डिजाइन के साथ आप मदद कर सकते हैं लगता है कि "थ्रेड मर चुका है" है:

  • कार्य-आधारित अतुल्यकालिक पैटर्न दिशानिर्देशों का पालन करें।
  • चूंकि आपका कोड बेस अधिक असीमित हो जाता है, यह प्रकृति में अधिक कार्यात्मक हो जाएगा (परंपरागत रूप से ऑब्जेक्ट उन्मुख के विपरीत)। यह सामान्य है और इसे गले लगाया जाना चाहिए।
  • चूंकि आपका कोड बेस अधिक असीमित हो जाता है, साझा-स्मृति समरूपता धीरे-धीरे संदेश-पासिंग समरूपता (यानी, ConcurrentExclusiveSchedulerPair नया ReaderWriterLock) विकसित होती है।
+0

ग्रेट उत्तर स्टीफन, लेकिन स्पष्टीकरण के लिए: अगर कॉन्फ़िगरएवाइट (झूठा) आंतरिक रूप से एसिंक विधि 'ए' द्वारा उपयोग किया जाता है, तो यदि मैं विधि 'ए' का इंतजार कर रहा हूं तो मैं किस संदर्भ में होने की उम्मीद करता हूं? थ्रेडपूल, या विधि 'ए' के ​​लिए एक प्रतीक्षा कॉल करने से पहले मूल संदर्भ फिर से शुरू होगा? –

+2

स्टीफन का जवाब काफी ठोस है। नोट, यदि आप अपने पुराने मॉडल पर मृत सेट हैं, तो आप हमेशा एक कस्टम रैपर का इंतजार कर सकते हैं (इसी तरह कॉन्फ़िगरएवाइट() काम करता है) और इसे कार्य/कार्य पर एक विस्तार विधि के रूप में हुक करें। उदाहरण के लिए, यदि आपकी एक्सटेंशन विधि को ResumeOn (TaskScheduler ts) कहा जाता है, तो कोड इस तरह दिख सकता है: फ़ू (...) का इंतजार करें। ResumeOn (ts); और फिर अपने स्वयं के कोड के रूप में सभी समान शेड्यूलिंग अर्थशास्त्र हैं, लेकिन सभी उन्नत प्रवाह/निष्पादन भलाई के साथ 'प्रतीक्षा' लाता है। –

+2

@ लॉरेंस: एसिंक विधियों की प्रत्येक "परत" इसके संदर्भ को पास करती है, लेकिन ऊपर नहीं। इसलिए यदि 'ए' 'कॉन्फ़िगरएवाइट (झूठी)' कहता है, तो यह थ्रेड पूल पर चलना समाप्त हो जाएगा। फिर, जब 'बी' कॉल 'ए() 'का इंतजार करता है, तो' बी '' प्रतीक्षा' के बाद * अपने * मूल संदर्भ में फिर से शुरू होगा। तथ्य यह है कि थ्रेड पूल पर 'ए' खत्म होने पर 'बी' के शेष पर कोई प्रभाव नहीं पड़ता है। –