2012-03-27 19 views
57

सी # 5.0 भाषा में जोड़े गए दो नए कीवर्ड async और await हैं, दोनों कॉलिंग थ्रेड को अवरुद्ध किए बिना सी # विधि को असीमित रूप से चलाने के लिए हाथ में काम करते हैं।नया सी # 5.0 'async' और 'प्रतीक्षा करें' कीवर्ड एकाधिक कोर का उपयोग करते हैं?

मेरा सवाल यह है कि, क्या ये विधियां वास्तव में एकाधिक कोर का लाभ लेती हैं और समानांतर में चलती हैं या कॉलर के समान थ्रेड कोर में एसिंक विधि चलती हैं?

+5

यह एसिंक विधि द्वारा लौटाई जाने वाली प्रतीक्षा योग्य वस्तु पर निर्भर करता है। – phoog

+1

न तो। वे सिर्फ वाक्यविन्यास चीनी हैं। थ्रेडिंग वर्तमान 'सिंक्रनाइज़ेशन कॉन्टेक्स्ट' और' टास्क 'पर निर्भर करता है जिसका आप इंतजार कर रहे हैं। – CodesInChaos

उत्तर

93

दो नए कीवर्ड्स async कर रहे हैं और इंतजार, बुला धागे को रोके बिना एसिंक्रोनस रूप से एक सी # विधि को चलाने के लिए जो दोनों के हाथ में हाथ काम करते हैं।

कि उद्देश्य सुविधा के भर में हो जाता है, लेकिन यह async/इंतजार सुविधा के लिए बहुत अधिक "क्रेडिट" देता है।

मुझे इस बिंदु पर बहुत स्पष्ट होना चाहिए: await जादूगर रूप से अतुल्यकालिक रूप से चलाने के लिए एक तुल्यकालिक विधि का कारण नहीं बनता है। यह एक नया धागा शुरू नहीं करता है और उदाहरण के लिए, नए धागे पर विधि चलाता है। जिस विधि को आप बुला रहे हैं वह वह चीज होनी चाहिए जो जानता है कि खुद को असीमित रूप से कैसे चलाया जाए। यह ऐसा करने का विकल्प कैसे चुनता है इसका व्यवसाय है।

मेरा सवाल यह है कि, क्या ये विधियां वास्तव में एकाधिक कोर का लाभ लेती हैं और समानांतर में चलती हैं या कॉलर के रूप में उसी थ्रेड कोर में एसिंक विधि चलती हैं?

फिर, उस विधि आप कॉल करने के लिए ऊपर पूरी तरह से है। यह सब await संकलक को उस प्रतिनिधि को विधि को फिर से लिखने का निर्देश देता है जिसे एसिंक्रोनस कार्य की निरंतरता के रूप में पारित किया जा सकता है। यही है, await FooAsync() का अर्थ है "कॉल FooAsync() और जो कुछ भी वापस आता है वह कुछ ऐसा होना चाहिए जो एसिंक्रोनस ऑपरेशन का प्रतिनिधित्व करता है जो अभी शुरू हुआ है। उस बात को बताएं कि जब यह पता चलता है कि एसिंक्रोनस ऑपरेशन किया जाता है, तो उसे इस प्रतिनिधि को कॉल करना चाहिए।" प्रतिनिधि के पास संपत्ति होती है जब इसे बुलाया जाता है, तो वर्तमान विधि फिर से शुरू होती है "जहां यह छोड़ा गया"।

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

एक सवाल आप से पूछना नहीं था, लेकिन शायद होना चाहिए:

जब अतुल्यकालिक कार्य समाप्त हो गया है और नियंत्रण ऊपर उठाता है जहां उसे रोका गया था, के रूप में यह पहले था एक ही धागे में निष्पादन है?

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

+1

मुझे आपकी व्याख्या यहां पसंद है और यह वास्तव में मुझे एसिंक को बेहतर ढंग से समझने और प्रतीक्षा करने में मदद करता है। – Icemanind

+1

यदि आप यूआई थ्रेड पर कुछ इंतजार करते हैं, तो नियंत्रण * आमतौर पर * यूआई थ्रेड पर फिर से उठाता है, लेकिन इसे नहीं करना है। यह "कुछ ऐसा है जो एसिंक्रोनस ऑपरेशन का प्रतिनिधित्व करता है" पर निर्भर करता है। उदाहरण के लिए, यह तब होता है जब आप 'someTask.ConfigureAwait (false)' का इंतजार करते हैं। – svick

2

async और await टीपीएल के आसपास आधारित हैं, उन्हें बहुत समान काम करना चाहिए। डिफ़ॉल्ट रूप से, आपको उनका इलाज करना चाहिए जैसे कि वे एक अलग थ्रेड पर चलते हैं।

4

एक एसिंक विधि एक प्रतीक्षा योग्य वस्तु (एक जिसमें GetAwaiter विधि है) लौटाती है, और संकलक await कीवर्ड के साथ विधि को कॉल करते समय उस ऑब्जेक्ट का उपभोग करने के लिए कोड उत्पन्न कर सकता है। आप इस तरह की विधि को बिना प्रतीक्षा कीवर्ड के कॉल करने के लिए स्वतंत्र हैं, और वस्तु को स्पष्ट रूप से उपभोग करते हैं।

ऑब्जेक्ट एक असीमित क्रिया को समाहित करता है, जो किसी अन्य धागे पर चल सकता है या नहीं। एरिक लिपर्ट का लेख Asynchrony in C# 5.0 part Four: It's not magic एसिंक्रोनस प्रोग्रामिंग का एक उदाहरण मानता है जिसमें केवल एक धागा शामिल है। सी # 5.0 भाषा में जुड़ते

65

एरिक लिपर्ट का एक उत्कृष्ट उत्तर है; मैं सिर्फ थोड़ा सा आगे async समांतरता का वर्णन करना चाहता था। इस उदाहरण में

static void Process() 
{ 
    Thread.Sleep(100); // Do CPU work. 
} 

static async Task Test() 
{ 
    await Task.Run(Process); 
    await Task.Run(Process); 
} 

, Test विधि थ्रेड पूल के लिए Process कतार होगा, और इसके पूर्ण होने पर, यह:

सरल "धारावाहिक" दृष्टिकोण जहां await सिर्फ एक एक समय में बात है कतार Process फिर से थ्रेड पूल में। Test विधि ~ 200ms के बाद पूरा हो जाएगी। किसी भी समय, केवल एक धागा वास्तव में आगे बढ़ रहा है। दो बार

static void Process() 
{ 
    Thread.Sleep(100); // Do CPU work. 
} 

static async Task Test() 
{ 
    // Start two background operations. 
    Task task1 = Task.Run(Process); 
    Task task2 = Task.Run(Process); 

    // Wait for them both to complete. 
    await Task.WhenAll(task1, task2); 
} 

इस उदाहरण में, Test विधि कतारों Process थ्रेड पूल के लिए, और फिर पूरा करने के लिए उन दोनों के लिए इंतजार कर रहा है:

इस parallelize करने के लिए एक आसान तरीका Task.WhenAll उपयोग करने के लिए है। Test विधि ~ 100ms के बाद पूरा हो जाएगी।

Task.WhenAll (और Task.WhenAny) के साथ async/await सरल समानांतरवाद समर्थन करने के लिए शुरू किए गए थे। हालांकि, टीपीएल अभी भी वहां है यदि आपको कुछ और उन्नत की जरूरत है (असली सीपीयू-बाध्य समांतर प्रसंस्करण टीपीएल के लिए बेहतर फिट है)। टीपीएल async/await के साथ अच्छी तरह से खेलता है।

मैं अपने into to async blog post में मूल async समांतरता को कवर करता हूं, साथ ही "संदर्भ" जिसे एरिक ने बताया है।

+1

इस उत्तर के लिए भी धन्यवाद! – Icemanind

+0

स्टीफन, आप उल्लेख करते हैं कि 'टीपीएल एसिंक/प्रतीक्षा के साथ अच्छी तरह से खेलता है'। क्या आप मुझे इस विशिष्ट विषय पर कुछ अच्छी जानकारी पर इंगित कर सकते हैं? – Patrick

+0

@ पैट्रिक: यदि आपको समांतरता * और * एसिंक्रोनि करने की आवश्यकता है, तो टीपीएल डेटाफ्लो देखें। –

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