c# - सभी सर्वर-साइड कोड के लिए ConfigureAwait को कॉल करने का सर्वोत्तम अभ्यास




asp.net-web-api task-parallel-library (3)

जब आपके पास सर्वर-साइड कोड होता है (यानी कुछ ApiController ) और आपके फ़ंक्शन एसिंक्रोनस होते हैं - इसलिए वे Task<SomeObject> वापस करते हैं - क्या यह सर्वोत्तम अभ्यास माना जाता है कि जब भी आप ConfigureAwait(false) कॉल करते हैं तो आप उन कार्यों का इंतजार करते हैं?

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

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

public class CustomerController : ApiController
{
    public async Task<Customer> Get(int id)
    {
        // you are on a particular thread here
        var customer = await SomeAsyncFunctionThatGetsCustomer(id).ConfigureAwait(false);

        // now you are on a different thread!  will that cause problems?
        return customer;
    }
}

आपके प्रश्न का संक्षिप्त उत्तर: नहीं। आपको इस तरह के आवेदन स्तर पर ConfigureAwait(false) को कॉल नहीं करना चाहिए।

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

यहां ConfigureAwait विधि (मेरे ब्लॉग पोस्ट से उद्धरण) के महत्व पर थोड़ा अधिक विस्तृत स्पष्टीकरण दिया गया है:

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

एक अवरुद्ध फैशन में, नई एसिंक्रोनस भाषा सुविधाओं का उपयोग करते समय, एक विधि का उपभोग करते समय, यदि आपके पास सिंक्रनाइज़ेशन कॉन्टेक्स्ट उपलब्ध है तो आप डेडलॉक के साथ समाप्त हो जाएंगे। जब आप अवरुद्ध फैशन में ऐसी विधियों का उपभोग कर रहे हैं (कार्य विधि के साथ कार्य पर प्रतीक्षा करें या परिणाम को सीधे परिणाम की संपत्ति से ले लें), तो आप एक ही समय में मुख्य धागे को अवरुद्ध कर देंगे। जब अंततः कार्य उस थ्रेडपूल में उस विधि के अंदर पूरा हो जाता है, तो यह मुख्य थ्रेड पर वापस पोस्ट करने के लिए निरंतरता का आह्वान करने जा रहा है क्योंकि SynchronizationContext.Current उपलब्ध और कब्जा कर लिया गया है। लेकिन यहां एक समस्या है: यूआई थ्रेड अवरुद्ध है और आपके पास डेडलॉक है!

इसके अलावा, यहां आपके लिए दो महान लेख हैं जो आपके प्रश्न के लिए बिल्कुल हैं:

आखिरकार, इस विषय पर लूसियान विस्चिक से बिल्कुल एक छोटा सा वीडियो है: Async लाइब्रेरी विधियों को कार्य का उपयोग करने पर विचार करना चाहिएकॉन्फ़िगर करेंएवाइट (झूठी)

उम्मीद है की यह मदद करेगा।


कॉन्फ़िगरएवाइट (झूठी) का उपयोग करने के साथ मैंने पाया सबसे बड़ा ड्रॉ यह है कि थ्रेड संस्कृति को सिस्टम डिफ़ॉल्ट पर वापस कर दिया जाता है। यदि आपने संस्कृति को कॉन्फ़िगर किया है जैसे ...

<system.web>
    <globalization culture="en-AU" uiCulture="en-AU" />    
    ...

और आप उस सर्वर पर होस्टिंग कर रहे हैं जिसकी संस्कृति एन-यूएस पर सेट की गई है, तो आप कॉन्फ़िगरएवाइट (झूठी) को CultureInfo कहा जाता है। कंटेंटकल्चर एन-एयू वापस कर देगा और आपको एन-यूएस प्राप्त करने के बाद मिलेगा। अर्थात

// CultureInfo.CurrentCulture ~ {en-AU}
await xxxx.ConfigureAwait(false);
// CultureInfo.CurrentCulture ~ {en-US}

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


अद्यतन: एएसपी.नेट कोर में SynchronizationContext नहीं है । यदि आप एएसपी.नेट कोर पर हैं, तो इससे कोई फर्क नहीं पड़ता कि आप ConfigureAwait(false) उपयोग करते हैं या नहीं।

एएसपी.नेट "पूर्ण" या "क्लासिक" या जो भी हो, इसके बाकी उत्तर अभी भी लागू होते हैं।

मूल पोस्ट (गैर-कोर एएसपी.नेट के लिए):

एएसपी.नेट टीम द्वारा इस वीडियो में एएसपी.नेट पर async का उपयोग करने की सबसे अच्छी जानकारी है।

मैंने पढ़ा था कि यह अधिक प्रदर्शनकारी है क्योंकि इसे थ्रेड संदर्भों को मूल धागे संदर्भ में वापस स्विच करने की आवश्यकता नहीं है।

यह यूआई अनुप्रयोगों के साथ सच है, जहां केवल एक यूआई थ्रेड है जिसे आपको "सिंक" करना होगा।

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

तो ConfigureAwait(false) आपको ASP.NET में थ्रेड कूद नहीं बचाता है; यह आपको अनुरोध संदर्भ के पुनः प्रवेश को बचाता है, लेकिन यह आमतौर पर बहुत तेज़ होता है। ConfigureAwait(false) उपयोगी हो सकता है यदि आप अनुरोध की समानांतर प्रक्रिया की थोड़ी सी मात्रा करने की कोशिश कर रहे हैं, लेकिन वास्तव में उन सभी परिदृश्यों के लिए टीपीएल बेहतर फिट है।

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

असल में, बस एक await कर कर ऐसा कर सकते हैं। एक बार आपकी async विधि await , विधि अवरुद्ध हो जाती है लेकिन थ्रेड थ्रेड पूल पर वापस आ जाता है। जब विधि जारी रखने के लिए तैयार होती है, तो थ्रेड पूल से कोई थ्रेड छीन लिया जाता है और विधि को फिर से शुरू करने के लिए उपयोग किया जाता है।

एएसपी.NET में ConfigureAwait एकमात्र अंतर बनाता है कि विधि को फिर से शुरू करते समय वह थ्रेड अनुरोध संदर्भ में प्रवेश करता है या नहीं।

मेरे पास मेरे एमएसडीएन आलेख में SynchronizationContext और मेरे async परिचय ब्लॉग पोस्ट पर अधिक पृष्ठभूमि जानकारी है।





async-await