11

मैं पहली बार कोड डाल चाहते हैं और उसके बाद स्थिति स्पष्ट और मेरे सवाल पर आधारित है कि पूछने के साथ इंतजार है:async/ConfigureAwait के continueOnCapturedContext पैरामीटर और अतुल्यकालिक निरंतरता के लिए SynchronizationContext

public partial class MainWindow : Window { 

    public MainWindow() { 
     InitializeComponent(); 
    } 

    private async void Button_Click_2(object sender, RoutedEventArgs e) { 

     var result = await GetValuesAsync(); 
     Foo.Text += result; 
    } 

    public async Task<string> GetValuesAsync() {   

     using (var httpClient = new HttpClient()) { 

      var response = await httpClient 
       .GetAsync("http://www.google.com") 
       .ConfigureAwait(continueOnCapturedContext: false); 


      // This is the continuation for the httpClient.GetAsync method. 
      // We shouldn't get back to sync context here 
      // Cuz the continueOnCapturedContext is set to *false* 
      // for the Task which is returned from httpClient.GetAsync method 
      var html = await GetStringAsync(); 

      // This is the continuation for the GetStringAsync method. 
      // Should I get back to sync context here? 
      // Cuz the continueOnCapturedContext is set to *true* 
      // for the Task which is returned from GetStringAsync 

      // However, GetStringAsync may be executed in another thread 
      // which has no knowledge for the sync context 
      // because the continueOnCapturedContext is set to *false* 
      // for the Task which is returned from httpClient.GetAsync method. 

      // But, on the other hand, GetStringAsync method also has a 
      // chance to be executed in the UI thread but we shouldn't be 
      // relying on that. 
      html += "Hey..."; 
      Foo.Text = html; 

      return html; 
     } 
    } 

    public async Task<string> GetStringAsync() { 

     await Task.Delay(1000); 
     return "Done..."; 
    } 
} 

यह एक काफी सरल WPF नमूना है जो .NET 4.5 पर चलता है और शायद बहुत अधिक समझ में नहीं आता है लेकिन इससे मुझे मेरी स्थिति की व्याख्या करने में मदद करनी चाहिए।

मेरे पास स्क्रीन पर एक बटन है जिसमें एक असीमित क्लिक ईवेंट है। जब आप GetValuesAsync कोड देखते हैं, तो आप await कीवर्ड का उपयोग दो बार देखेंगे। पहले उपयोग के साथ, मैंने Task.ConfigureAwait विधि false पर पैरामीटर सेट किया है। तो, यह इंगित करता है कि मैं SynchronizationContext.Current के अंदर निष्पादित होने की मेरी निरंतरता नहीं चाहता हूं। अब तक सब ठीक है।

दूसरे await उपयोग पर (GetStringAsync विधि के साथ), मैंने ConfigureAwait विधि को कॉल नहीं किया था। इसलिए, मैंने मूल रूप से संकेत दिया कि GetStringAsync विधि की निरंतरता के लिए वर्तमान सिंक्रनाइज़ेशन संदर्भ पर वापस आने के लिए चाहते हैं। इसलिए, जैसा कि आप देख सकते हैं, मैं निरंतरता के अंदर TextBlock.Text (जो यूआई थ्रेड से संबंधित) संपत्ति सेट करने का प्रयास करता हूं।

जब मैं आवेदन चलाने के लिए और बटन क्लिक करें, मैं एक अपवाद मुझे निम्न संदेश दे रही है मिलती है: क्योंकि एक अलग धागा यह मालिक

बुला धागा इस वस्तु का उपयोग नहीं कर सकते हैं।

सबसे पहले, यह मेरे लिए कोई मतलब नहीं बनाया है और मैंने सोचा था कि मैं एक बग की खोज की है, लेकिन फिर, मैंने महसूस किया कि GetStringAsync एक और धागा (अत्यधिक संभावना) जो यूआई धागा तुलना में अलग है और कोई है में निष्पादित किया जा सकता सिंक संदर्भ के लिए ज्ञान क्योंकि continueOnCapturedContextfalse पर Task के लिए सेट किया गया है जो httpClient.GetAsync विधि से वापस लौटाया गया है।

क्या यह मामला यहां है? इसके अलावा, इस मामले में, GetStringAsync विधि को यूआई थ्रेड पर वापस पोस्ट करने का मौका है httpClient.GetAsync विधि निरंतरता UI थ्रेड के अंदर निष्पादित की जा सकती है?

मेरे पास कोड के अंदर कुछ टिप्पणियां भी हैं। कोड के अंदर मेरे प्रश्नों और टिप्पणियों को ध्यान में रखते हुए, क्या मुझे यहां कुछ याद आ रही है?

+0

क्या यह उत्तर मदद करता है? http://stackoverflow.com/a/12357113/171121 –

उत्तर

11

जब आप ConfigureAwait(false) फोन, विधि के बाकी एक धागा पूल धागा पर निष्पादित किया जाएगा जब तकTask आप कर रहे हैं await आईएनजी पहले से ही पूरा हो गया है।

GetAsync लगभग निश्चित रूप से असीमित रूप से चलाएगा, मैं थ्रेड पूल थ्रेड पर चलाने के लिए GetStringAsync की अपेक्षा करूंगा।

public async Task<string> GetValuesAsync() {   

    using (var httpClient = new HttpClient()) { 

     var response = await httpClient 
      .GetAsync("http://www.google.com") 
      .ConfigureAwait(continueOnCapturedContext: false); 

     // And now we're on the thread pool thread. 

     // This "await" will capture the current SynchronizationContext... 
     var html = await GetStringAsync(); 
     // ... and resume it here. 

     // But it's not the UI SynchronizationContext. 
     // It's the ThreadPool SynchronizationContext. 
     // So we're back on a thread pool thread here. 

     // So this will raise an exception. 
     html += "Hey..."; 
     Foo.Text = html; 

     return html; 
    } 
} 

इसके अलावा, इस मामले में, इस बात की संभावना के लिए GetStringAsync विधि यूआई धागा अंदर निष्पादित किया जा सकता httpClient.GetAsync विधि निरंतरता bacuse यूआई धागा करने के लिए वापस पोस्ट किया जाता है?

एक ही रास्ता GetStringAsync यूआई धागा पर चलेगा अगर GetAsync पूरा करता है इससे पहले कि यह वास्तव में await एड है। अत्यधिक संभावना नहीं है।

इस कारण से, मैं संदर्भ अब जरूरत है एक बार हरawait के लिए ConfigureAwait(false) उपयोग करने के लिए पसंद करते हैं।

+0

धन्यवाद! आपकी आखिरी वाक्य जिस तरह से मैं निम्नलिखित मानता हूं (मैं रहा हूं लेकिन अब मैं उस पर अधिक जोर देने जा रहा हूं)। यह ध्यान देने योग्य अंतर नहीं करेगा लेकिन 'ConfigureAwait (false)' का उपयोग करके हमें अनावश्यक 'सिंक्रनाइज़ेशन कॉन्टेक्स्ट' चेक से भी बचाया जाएगा यदि इसकी आवश्यकता नहीं है। – tugberk

+0

"बेहद असंभव" निश्चित रूप से पर्याप्त नहीं है। या तो यह 100% होना चाहिए या आपके कोड को दोनों मामलों को सहन करने की आवश्यकता है। – usr

+1

मैं सामान्य रूप से सहमत हूं। एक बार संदर्भ की आवश्यकता होने के बाद मैं हर 'प्रतीक्षा' के लिए 'कॉन्फ़िगरएवाइट (झूठी)' का उपयोग करना पसंद करता हूं। –

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