मेरे पास एक छोटा प्रोजेक्ट है - WinForms ऑन .net फ्रेमवर्क - बस एक छोटा परीक्षण:
private void button9_Click(object sender, EventArgs e)
{
string text = GetTitleAsync().Result;
button9.Text = text;
}
private async Task<string> GetTitleAsync()
{
await Task.Delay(3000);
return "Hello!";
}
जैसे ही मैंने एप्लिकेशन चलाया, बटन पर क्लिक करना: "बटन 9" - एक डेड लॉक का कारण बना, (चूंकि थ्रेड ".result" पर लटका हुआ था)
GetTitleAsync() इस तरह लिखना:
private async Task<string> GetTitleAsync()
{
await Task.Delay(3000).ConfigureAwait(false);
return "Hello!";
}
गतिरोध हल किया - और आवेदन ठीक चला।
पर समझ नहीं आता कैसे ?
मुझे उम्मीद थी, कि ".ConfigureAwait(false)" का उपयोग करने से ऐसी स्थिति पैदा होगी जिसमें:
"बटन 9. टेक्स्ट = टेक्स्ट;" एक से भिन्न थ्रेड पर निष्पादित किया जाता है, जिस पर UI बनाया गया था, और एक अपवाद फेंक दिया जाएगा!
लेकिन यह उत्कृष्ट काम करता है! कैसे??
1 उत्तर
मुझे उम्मीद थी, कि ".ConfigureAwait(false)" का उपयोग करने से ऐसी स्थिति पैदा होगी जिसमें "button9.Text = text;" एक से भिन्न थ्रेड पर निष्पादित किया जाता है, जिस पर UI बनाया गया था, और एक अपवाद फेंक दिया जाएगा! लेकिन यह उत्कृष्ट काम करता है! कैसे??
मैं अपना async
/await
परिचय पढ़ने की सलाह देता हूं; परिचय के लिए बहुत अधिक विस्तार में जाने के बिना, मैं async
/await
और उनके संदर्भों के बारे में जानने के लिए आवश्यक सभी चीजों को शामिल करने का प्रयास करता हूं।
विशेष रूप से, उस पोस्ट से दो बिंदु हैं जो ध्यान देने योग्य हैं:
- प्रत्येक
async
विधि कॉलिंग थ्रेड पर समकालिक रूप से निष्पादित करना शुरू कर देती है। await
किसी संदर्भ को तब तक कैप्चर करता है जब तक कि आपConfigureAwait(false)
का उपयोग नहीं करते।
तो, इस कोड के माध्यम से चलना:
private void button9_Click(object sender, EventArgs e)
{
string text = GetTitleAsync().Result;
button9.Text = text;
}
private async Task<string> GetTitleAsync()
{
await Task.Delay(3000).ConfigureAwait(false);
return "Hello!";
}
ऐसा होता है, क्रम में, विशेष ध्यान दिया जाता है कि कौन सा धागा किस कोड को चलाता है:
button9_Click
UI थ्रेड परGetTitleAsync()
कॉल करता है।GetTitleAsync()
Task.Delay(3000)
को कॉल करता है और 3 सेकंड में पूरा होने वाला कार्य वापस प्राप्त करता है।GetTitleAsync()
ConfigureAwait(false)
को कॉल करता है और एक कॉन्फ़िगर किया हुआ वेटर वापस प्राप्त करता है जो वर्तमान (UI) संदर्भ में फिर से शुरू नहीं होगा।GetTitleAsync()
कार्य पूरा होने के लिए अतुल्यकालिक रूप से प्रतीक्षा करने के लिएawait
का उपयोग करता है। यहawait
वर्तमान (UI) संदर्भ में फिर से शुरू नहीं होगा क्योंकिawait
को कॉन्फ़िगर नहीं किया गया है।await
कार्य की जांच करता है और देखता है कि यह पूरा नहीं हुआ है, इसलिए यह अपने कॉलर को अपूर्णTask<string>
लौटाता है।button9_Click
उस कार्य पर.Result
को कॉल करता है। यह UI थ्रेड को तब तक ब्लॉक करता है जब तक कि कार्य पूरा नहीं हो जाता (यानी,GetTitleAsync()
निष्पादन समाप्त हो जाता है)।- तीन सेकंड बाद,
Task.Delay(3000)
से लौटा हुआ कार्य पूरा होता है। GetTitleAsync()
अपनेawait
के बाद क्रियान्वित करना फिर से शुरू करता है। चूंकि यह एक कॉन्फ़िगर किया गयाawait
था, यह थ्रेड पूल थ्रेड पर क्रियान्वित करना जारी रखता है।GetTitleAsync()
रिटर्न"Hello!"
। यह थ्रेड पूल थ्रेड पर किया जाता है।- एक मान लौटाने से,
GetTitleAsync()
अब पूरा हो गया है, औरTask<string>
जो पहले लौटा था, अब परिणाम मान के साथ पूरा हो गया है। यह पूर्णता थ्रेड पूल थ्रेड पर भी होती है। - चूंकि कार्य अब पूरा हो गया है, UI थ्रेड अब अवरुद्ध नहीं है, और यह
button9_Click
निष्पादित करना जारी रखता है। button9_Click
UI थ्रेड परbutton9.Text = text;
निष्पादित करता है।
संबंधित सवाल
नए सवाल
winforms
WinForms, विंडोज फॉर्म को दिया जाने वाला अनौपचारिक नाम है, जो Microsoft .NET फ्रेमवर्क और मोनो में एक GUI क्लास लाइब्रेरी है। इस टैग में प्रश्नों को भी लक्ष्य ढांचे ([.net] या [मोनो]) के साथ टैग किया जाना चाहिए और आमतौर पर एक प्रोग्रामिंग भाषा टैग के साथ टैग किया जाना चाहिए।
.ConfigureAwait(false);
को वहां से हटा दें, बदलें:private async void button9_Click
औरstring text = await GetTitleAsync();
ConfigureAwait(false);
एक अलग थ्रेड पर निरंतरता को फिर से शुरू करने का कारण बनता है, लेकिनWindowsFormsSynchronizationContext
मजबूत है, पहली प्रतीक्षा UI थ्रेड में फिर से शुरू होगी। तोResult
करेंगे। लेकिन आप async कोड को ब्लॉक नहीं करते हैं।