C # 5 async समर्थन UI थ्रेड सिंक्रनाइज़ेशन समस्याओं को कैसे मदद करेगा?


16

मैंने कहीं सुना है कि C # 5 async-wait इतना भयानक होगा कि आपको ऐसा करने के लिए परेशान नहीं होना पड़ेगा:

if (InvokeRequired)
{
    BeginInvoke(...);
    return;
}
// do your stuff here

ऐसा लगता है कि कॉलर के मूल धागे में एक प्रतीक्षित ऑपरेशन का कॉलबैक होगा। एरिक लिपर्ट और एंडर्स हेजलबर्ग द्वारा कई बार कहा गया है कि यह सुविधा UI (विशेष रूप से टच डिवाइस UI) को अधिक उत्तरदायी बनाने की आवश्यकता से उत्पन्न हुई है।

मुझे लगता है कि इस तरह की सुविधा का एक सामान्य उपयोग कुछ इस तरह होगा:

public class Form1 : Form
{
    // ...
    async void GetFurtherInfo()
    {
        var temperature = await GetCurrentTemperatureAsync();
        label1.Text = temperature;
    }
}

यदि केवल कॉलबैक का उपयोग किया जाता है तो लेबल टेक्स्ट सेट करना एक अपवाद को बढ़ाएगा क्योंकि यह UI के थ्रेड में निष्पादित नहीं किया जा रहा है।

अब तक मुझे इस बात की पुष्टि करने वाला कोई भी संसाधन नहीं मिला। क्या किसी को इसके बारे में पता है? क्या कोई दस्तावेज तकनीकी रूप से समझा रहा है कि यह कैसे काम करेगा?

कृपया एक विश्वसनीय स्रोत से एक लिंक प्रदान करें, बस "हां" का जवाब न दें।


यह अत्यधिक संभावना नहीं है, कम से कम insofar के रूप में awaitकार्यक्षमता का संबंध है। यह निरंतरता गुजरने के लिए सिंटैक्टिक शुगर का एक बहुत कुछ है । संभवतः WinForms में कुछ अन्य असंबंधित सुधार हैं जो मदद करने वाले हैं? यह .NET फ्रेमवर्क के अंतर्गत ही आएगा, हालाँकि, और विशेष रूप से C # नहीं।
हारून

@ मैं सहमत हूं, इस कारण मैं सवाल ठीक पूछ रहा हूं। मैंने यह स्पष्ट करने के लिए प्रश्न संपादित किया कि मैं कहाँ से आ रहा हूँ। अजीब लगता है कि वे इस सुविधा को बनाएंगे और अभी भी आवश्यकता होगी कि हम कोड के कुख्यात InvokeRequired शैली का उपयोग करें।
एलेक्स

जवाबों:


17

मुझे लगता है कि आप यहां कुछ चीजें भ्रमित कर रहे हैं। आप जो पूछ रहे हैं, वह पहले से ही संभव है System.Threading.Tasks, asyncऔर awaitC # 5 में केवल उसी सुविधा के लिए थोड़ा अच्छा सिंटरैक्टिक शुगर प्रदान करने जा रहे हैं।

आइए एक Winforms उदाहरण का उपयोग करें - फॉर्म पर एक बटन और एक टेक्स्टबॉक्स ड्रॉप करें और इस कोड का उपयोग करें:

private void button1_Click(object sender, EventArgs e)
{
    Task.Factory.StartNew<int>(() => DelayedAdd(5, 10))
        .ContinueWith(t => DelayedAdd(t.Result, 20))
        .ContinueWith(t => DelayedAdd(t.Result, 30))
        .ContinueWith(t => DelayedAdd(t.Result, 50))
        .ContinueWith(t => textBox1.Text = t.Result.ToString(),
            TaskScheduler.FromCurrentSynchronizationContext());
}

private int DelayedAdd(int a, int b)
{
    Thread.Sleep(500);
    return a + b;
}

इसे चलाएं और आप देखेंगे कि (ए) यह यूआई थ्रेड को ब्लॉक नहीं करता है और (बी) आपको सामान्य "क्रॉस-थ्रेड ऑपरेशन वैध नहीं" त्रुटि मिलती है - जब तक कि आप TaskSchedulerतर्क को अंतिम से नहीं हटाते हैं ContinueWith, तुम कौन सा केस करोगे

यह बोग-स्टैंडर्ड कंटीन्यू पासिंग स्टाइल है । जादू TaskSchedulerवर्ग में होता है और विशेष रूप से उदाहरण द्वारा पुनर्प्राप्त किया जाता है FromCurrentSynchronizationContext। इसे किसी भी निरंतरता में पास करें और आप इसे बताएं कि निरंतरता को FromCurrentSynchronizationContextविधि नामक धागे पर चलना चाहिए - इस मामले में, यूआई धागा।

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

private async void button1_Click(object sender, EventArgs e)
{
    int a = await DelayedAddAsync(5, 10);
    int b = await DelayedAddAsync(a, 20);
    int c = await DelayedAddAsync(b, 30);
    int d = await DelayedAddAsync(c, 50);
    textBox1.Text = d.ToString();
}

private async Task<int> DelayedAddAsync(int a, int b)
{
    Thread.Sleep(500);
    return a + b;
}

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

सिद्धांत रूप में मतभेद बहुत अधिक महत्वपूर्ण हैं। दूसरे उदाहरण में, button1_Clickविधि में हर एक पंक्ति वास्तव में UI थ्रेड में निष्पादित होती है, लेकिन कार्य स्वयं ( DelayedAddAsync) पृष्ठभूमि में चलता है। पहले उदाहरण में, सब कुछ पृष्ठभूमि में चलता है , असाइनमेंट को छोड़करtextBox1.Text जो हमने UI थ्रेड के सिंक्रनाइज़ेशन संदर्भ से स्पष्ट रूप से जुड़ा हुआ है।

यह वास्तव में दिलचस्प है await- यह तथ्य कि एक वेटर बिना किसी अवरोधक कॉल के एक ही विधि से अंदर और बाहर कूदने में सक्षम है । आप कॉल करते हैं await, वर्तमान थ्रेड प्रोसेसिंग संदेशों पर वापस जाता है, और जब यह हो जाता है, तो वेटर ठीक उसी जगह उठाएगा, जहां से छोड़ा था, उसी थ्रेड में इसे छोड़ दिया। लेकिन प्रश्न में आपके Invoke/ BeginInvokeइसके विपरीत, मैं ' मुझे यह कहने के लिए खेद है कि आपको ऐसा करना बंद कर देना चाहिए था।


यह बहुत दिलचस्प है @Aaronaught। मैं निरंतरता की शैली से अवगत था, लेकिन इस पूरे "सिंक्रनाइज़ेशन संदर्भ" चीज़ के बारे में नहीं जानता था। क्या कोई दस्तावेज़ इस सिंक संदर्भ को C # 5 async-wait से जोड़ रहा है? मैं समझता हूं कि यह एक मौजूदा विशेषता है लेकिन तथ्य यह है कि वे इसे एक बड़ी बात की तरह डिफ़ॉल्ट ध्वनियों द्वारा उपयोग कर रहे हैं, विशेष रूप से क्योंकि यह प्रदर्शन में कुछ प्रमुख प्रभाव होना चाहिए, है ना? उस पर कोई और टिप्पणी? वैसे आपके उत्तर के लिए धन्यवाद।
एलेक्स

1
@ एलेक्स: उन सभी अनुवर्ती प्रश्नों के उत्तर के लिए, मैं आपको Async प्रदर्शन पढ़ने का सुझाव देता हूं : Async और Await की लागत को समझना । "केयर के बारे में संदर्भ" खंड बताता है कि यह सब कैसे सिंक्रनाइज़ेशन संदर्भ से संबंधित है।
Aaronaught

(वैसे, सिंक्रनाइज़ेशन संदर्भ नए नहीं हैं; वे २.० के बाद से फ्रेमवर्क में हैं। टीपीएल ने उन्हें उपयोग करने के लिए बहुत आसान बना दिया है।)
२०:०२

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

2
@ एलेक्स: मुझे लगता है कि आप सही स्थानों पर नहीं दिख रहे थे । मुझे नहीं पता कि आपको क्या बताना है; .NET समुदाय के बड़े हिस्से हैं जिन्हें पकड़ने में लंबा समय लगता है। नरक, मैं अभी भी ArrayListनए कोड में कक्षा का उपयोग करते हुए कुछ कोडर देखता हूं । मेरे पास अभी भी आरएक्स के साथ बमुश्किल कोई अनुभव है। लोग वही सीखते हैं जो उन्हें जानने और साझा करने की आवश्यकता होती है जो वे पहले से ही जानते हैं, भले ही वे पहले से ही जानते हों। यह उत्तर कुछ वर्षों में पुराना हो सकता है।
Aaronaught

4

हां, UI थ्रेड के लिए, कॉल करने वाले के मूल थ्रेड पर वेट ऑपरेशन का कॉलबैक होगा।

एरिक लिपर्ट ने एक साल पहले इसके बारे में एक 8-भाग श्रृंखला लिखी थी: शानदार एडवेंचर्स इन कोडिंग

संपादित करें: और यहाँ एंडर्स '// बिल्ड / प्रस्तुति: चैनल 9

BTW, क्या आपने देखा कि यदि आप "// बिल्ड /" को उल्टा करते हैं, तो आपको "/ plinq //"; ;-) मिलता है।


3

जॉन स्कीट ने C # 5 में Async विधियों को शामिल करते हुए एक उत्कृष्ट प्रस्तुति दी जो आपको बेहद उपयोगी लग सकती है:

http://skillsmatter.com/podcast/home/async-methods


एक ही लेखक द्वारा EduAsync भी Async के बारे में जानकारी का एक अच्छा स्रोत हो सकता है।
मैथ्यू
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.