मुझे लगता है कि आप यहां कुछ चीजें भ्रमित कर रहे हैं। आप जो पूछ रहे हैं, वह पहले से ही संभव है System.Threading.Tasks
, async
और await
C # 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
इसके विपरीत, मैं ' मुझे यह कहने के लिए खेद है कि आपको ऐसा करना बंद कर देना चाहिए था।
await
कार्यक्षमता का संबंध है। यह निरंतरता गुजरने के लिए सिंटैक्टिक शुगर का एक बहुत कुछ है । संभवतः WinForms में कुछ अन्य असंबंधित सुधार हैं जो मदद करने वाले हैं? यह .NET फ्रेमवर्क के अंतर्गत ही आएगा, हालाँकि, और विशेष रूप से C # नहीं।