2016-04-01 15 views
15

मैं नीचे दी गई विधि है:मैं एक Async विधि को एक Async विधि से कैसे कॉल करूं?

public string RetrieveHolidayDatesFromSource() { 
     var result = this.RetrieveHolidayDatesFromSourceAsync(); 
     /** Do stuff **/ 
     var returnedResult = this.TransformResults(result.Result); /** Where result gets used **/ 
     return returnedResult; 
    } 


    private async Task<string> RetrieveHolidayDatesFromSourceAsync() { 
     using (var httpClient = new HttpClient()) { 
      var json = await httpClient.GetStringAsync(SourceURI); 
      return json; 
     } 
    } 

से काम नहीं होता और किसी भी परिणाम ठीक से वापस नहीं जा रहा है। मुझे यकीन नहीं है कि परिणाम के इंतजार को मजबूर करने के लिए मुझे एक बयान क्यों खो रहा है? मैं एक स्ट्रिंग वापस करने के लिए पुनर्प्राप्ति होलीडेडेट्सफ्रॉमसोर्स() विधि चाहता हूं।

नीचे ठीक काम करता है लेकिन यह तुल्यकालिक है और मुझे विश्वास है कि इसे बेहतर किया जा सकता है? ध्यान दें कि नीचे सिंक्रोनस है जिसमें मैं असीमित में बदलना चाहता हूं लेकिन किसी कारण से मेरे सिर को लपेटने में असमर्थ हूं।

public string RetrieveHolidayDatesFromSource() { 
     var result = this.RetrieveHolidayDatesFromSourceAsync(); 
     /** Do Stuff **/ 

     var returnedResult = this.TransformResults(result); /** This is where Result is actually used**/ 
     return returnedResult; 
    } 


    private string RetrieveHolidayDatesFromSourceAsync() { 
     using (var httpClient = new HttpClient()) { 
      var json = httpClient.GetStringAsync(SourceURI); 
      return json.Result; 
     } 
    } 

क्या मुझे कुछ याद आ रही है?

नोट: किसी कारण से, जब मैं Async विधि ऊपर ब्रेकपाइंट, जब यह लाइन के लिए हो जाता है "var json = httpClient.GetStringAsync (SourceURI) का इंतजार है" के लिए यह सिर्फ ब्रेकप्वाइंट से बाहर चला जाता है और मैं वापस में नहीं जा सकते प्रक्रिया।

उत्तर

23

क्या मुझे कुछ याद आ रही है?

हां। असीमित कोड - इसकी प्रकृति से - इसका तात्पर्य है कि ऑपरेशन चालू होने पर वर्तमान थ्रेड का उपयोग नहीं किया जाता है। सिंक्रोनस कोड - इसकी प्रकृति से - यह दर्शाता है कि ऑपरेशन प्रगति पर है, जबकि मौजूदा थ्रेड अवरुद्ध है। यही कारण है कि सिंक्रोनस कोड से असीमित कोड को सचमुच कॉल करना भी समझ में नहीं आता है। वास्तव में, जैसा कि मैंने अपने ब्लॉग पर वर्णन किया है, a naive approach (using Result/Wait) can easily result in deadlocks

विचार करने वाली पहली बात यह है कि: मेरा एपीआई तुल्यकालिक या असीमित हो सकता है? यदि यह I/O (जैसा कि इस उदाहरण में है) से संबंधित है, तो यह should be asynchronous है।

public async Task<string> RetrieveHolidayDatesFromSourceAsync() { 
    var result = await this.DoRetrieveHolidayDatesFromSourceAsync(); 
    /** Do stuff **/ 
    var returnedResult = this.TransformResults(result); /** Where result gets used **/ 
    return returnedResult; 
} 

मैं अपने async best practices article में वर्णन के रूप में, आप "सभी तरह async" जाना चाहिए: तो, यह एक और अधिक उचित डिजाइन किया जाएगा। यदि आप नहीं करते हैं, तो आपको एसिंक से किसी भी लाभ का कोई फायदा नहीं होगा, तो परेशान क्यों?

लेकिन मान लीजिए कि आप अंततः async जा रहा में रुचि रखते हैं, लेकिन अभी आप सब कुछ नहीं बदल सकते हैं, तो आप सिर्फ अपने अनुप्रयोग के हिस्सा बदलना चाहते हैं। यह एक बहुत ही आम स्थिति है।

उस स्थिति में, दोनों सिंक्रोनस और एसिंक्रोनस एपीआई का खुलासा करने का उचित दृष्टिकोण है। आखिरकार, अन्य सभी कोड को अपग्रेड करने के बाद, सिंक्रोनस एपीआई को हटाया जा सकता है।मैं अपने article on brownfield async development में इस तरह के परिदृश्य के लिए विभिन्न विकल्पों का पता लगाता हूं;

public string RetrieveHolidayDatesFromSource() { 
    return this.DoRetrieveHolidayDatesFromSourceAsync(sync: true).GetAwaiter().GetResult(); 
} 

public Task<string> RetrieveHolidayDatesFromSourceAsync() { 
    return this.DoRetrieveHolidayDatesFromSourceAsync(sync: false); 
} 

private async Task<string> DoRetrieveHolidayDatesFromSourceAsync(bool sync) { 
    var result = await this.GetHolidayDatesAsync(sync); 
    /** Do stuff **/ 
    var returnedResult = this.TransformResults(result); 
    return returnedResult; 
} 

private async Task<string> GetHolidayDatesAsync(bool sync) { 
    using (var client = new WebClient()) { 
    return sync 
     ? client.DownloadString(SourceURI) 
     : await client.DownloadStringTaskAsync(SourceURI); 
    } 
} 

यह दृष्टिकोण कोड दोहराव से बचा जाता है और भी अन्य "सिंक-ओवर-async" antipattern समाधान के साथ आम किसी भी गतिरोध या reentrancy समस्याओं से बचा जाता है: मेरी निजी पसंदीदा "bool पैरामीटर हैक" है, जो इस प्रकार दिखाई देगा है।

ध्यान दें कि मैं अभी भी परिणामी कोड को ठीक से एसिंक्रोनस एपीआई के पथ पर "मध्यवर्ती चरण" के रूप में मानता हूं। विशेष रूप से, आंतरिक कोड को WebClient (जो सिंक और एसिंक दोनों का समर्थन करता है) को HttpClient (जो केवल एसिंक का समर्थन करता है) के बजाय वापस गिरना पड़ता था। एक बार सभी कॉलिंग कोड RetrieveHolidayDatesFromSourceAsync और RetrieveHolidayDatesFromSource का उपयोग करने के लिए बदल दिए जाने के बाद, मैं इसे फिर से देखूंगा और सभी तकनीकी ऋण को हटा दूंगा, इसे HttpClient का उपयोग करने के लिए बदल रहा हूं और केवल एसिंक-केवल हो सकता हूं।

+1

क्या 'सार्वजनिक कार्य पुनर्प्राप्ति होलीडेडेट्सफ्रॉमसोर्सएसिंक() 'एक' प्रतीक्षा 'गायब है? –

+3

@ निकवेवर: नहीं। यह 'async' नहीं है, इसलिए यह' प्रतीक्षा 'का उपयोग नहीं कर सकता है। –

+0

मैं देखता हूं। मैं सोच रहा था क्योंकि विधि का नाम अंत में "Async" कहता है। यह async पर क्यों सेट नहीं है? –

2
public string RetrieveHolidayDatesFromSource() { 
    var result = this.RetrieveHolidayDatesFromSourceAsync().Result; 
    /** Do stuff **/ 
    var returnedResult = this.TransformResults(result.Result); /** Where result gets used **/ 
    return returnedResult; 
} 

आप async कॉल करने के लिए .Result जोड़ेंगे, तो वह निष्पादित और परिणाम के आने का इंतजार करेंगे, यह तुल्यकालिक होने के लिए मजबूर कर रहा

अद्यतन:

private static string stringTest() 
{ 
    return getStringAsync().Result; 
} 

private static async Task<string> getStringAsync() 
{ 
    return await Task.FromResult<string>("Hello"); 
} 
static void Main(string[] args) 
{ 
    Console.WriteLine(stringTest()); 

} 

टिप्पणी को संबोधित करने के लिए: यह किसी भी समस्या के बिना काम करता है।

+1

मुझे नहीं लगता कि यह काम कर रहा है क्योंकि मेरे पास पहले से ही "परिणाम। परिणाम" है। यह होने के बाद। पुनर्प्राप्ति होलीडेडेट्सप्रॉमसोर्सएसिंक()। परिणाम परिणाम को एक गैर-कार्य ऑब्जेक्ट में बदल देगा जो "var returnResult = this.TransformResults (result.Result)" में त्रुटि उत्पन्न करेगा। –

+0

मैंने आपको अपना कोड अपडेट करने के लिए अपडेट किया है। आप देख सकते हैं कि getStringAsync एक async विधि है जिसे एक सिंक की गई विधि (स्ट्रिंगटेस्ट()) में कहा जाता है, मुझे त्रुटियों के बिना वांछित आउटपुट प्राप्त होता है। आपको क्या त्रुटि मिल रही है? –

+4

"यह किसी भी समस्या के बिना काम करता है":) ... आप थोड़ा अच्छा हो सकते हैं और वास्तव में कंसोल ऐप्स के बाहर उपयोग किए जाने पर परिणामस्वरूप डेडलॉक से निपटने का तरीका बता सकते हैं। –

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