2012-11-23 25 views
16

मैं C# 5 की async सुविधा के लिए नया हूं। मैं इन दो कार्यान्वयन के बीच अंतर को समझने के लिए कोशिश कर रहा हूँ:Async- प्रतीक्षा करें कार्य। Run बनाम HttpClient.GetAsync

कार्यान्वयन 1:

private void Start() 
{ 
    foreach(var url in urls) 
    { 
     ParseHtml(url); 
    } 
} 

private async void ParseHtml(string url) 
{ 
    var query = BuildQuery(url); //BuildQuery is some helper method 
    var html = await DownloadHtml(query); 
    //... 
    MyType parsedItem = ParseHtml(html); 
    SaveTypeToDB(parsedItem); 
} 

private async Task<string> DownloadHtml(string query) 
{ 
    using (var client = new HttpClient()) 
    try 
    { 
     var response = await client.GetAsync(query); 
     return (await response.Content.ReadAsAsync<string>()); 
    } 
    catch (Exception ex) 
    { 
     Logger.Error(msg, ex); 
     return null; 
    } 
} 

कार्यान्वयन 2:

private void DoLoop() 
{ 
    foreach(var url in urls) 
    { 
     Start(url); 
    } 
} 

private async void Start(url) 
{ 
    await Task.Run(() => ParseHtml(url)) ; 
} 

private void ParseHtml(string url) 
{ 
    var query = BuildQuery(url); //BuildQuery is some helper method 
    var html = DownloadHtml(query); 
    //... 
    MyType parsedItem = ParseHtml(html); 
    SaveTypeToDB(parsedItem); 
} 

private string DownloadHtml(string query) 
{ 
    using (var client = new WebClient()) 
    { 
     try 
     { 
      return client.DownloadString(query); 
     } 
     catch (Exception ex) 
     { 
      Logger.Error(msg, ex); 
      return null; 
     } 
    } 
} 

मैं नहीं बल्कि दूसरे कार्यान्वयन का उपयोग करेंगे क्योंकि इसे मेरे कोड में विधियों पर कम 'async' हस्ताक्षर की आवश्यकता होगी। मैं समझने की कोशिश कर रहा हूं कि एचटीपी क्लाइंट क्लास का उपयोग करके एक नया कार्य बनाकर इसका क्या फायदा है?

क्या दो कार्यान्वयन के बीच कोई अंतर है?

+0

'async' हस्ताक्षर '- उनके बारे में परवाह नहीं है। पुराने कोड के साथ संगत रहने के लिए "async" सिर्फ "मार्कर" है। प्री-5.0 में आपके पास "प्रतीक्षा" नाम के साथ चर/फ़ंक्शन हो सकते हैं। लेकिन चूंकि पुरानी विधियों में "async" कीवर्ड नहीं है, इसलिए कोड अभी भी सी # 5.0 के साथ संकलित (w/o परिवर्तन) करेगा। – igrimpe

उत्तर

28

मैं दूसरे कार्यान्वयन का उपयोग करता हूं क्योंकि इसे मेरे कोड में विधियों पर कम 'async' हस्ताक्षर की आवश्यकता होगी।

यह बहुत विषम औचित्य की तरह लगता है। आप मौलिक रूप से "कुछ हद तक असीमित रूप से निष्पादित करने की कोशिश कर रहे हैं" - तो यह स्पष्ट क्यों न करें?

क्या दो कार्यान्वयन के बीच कोई अंतर है?

बिल्कुल। दूसरा कार्यान्वयन पूरा होने के अनुरोध की प्रतीक्षा करते हुए WebClient.DownloadString ब्लॉक के दौरान एक धागा बांध देगा। पहले संस्करण में कोई अवरुद्ध धागा नहीं है - अनुरोध समाप्त होने पर यह आग की निरंतरता पर निर्भर करता है।

इसके अतिरिक्त, अपने Logger.Error कॉल पर विचार करें। Async संस्करण में, जो अभी भी मूल कॉलिंग कोड के संदर्भ में निष्पादित होगा। तो यदि यह कहता है, एक विंडोज़ फॉर्म यूआई है, तो आप अभी भी यूआई थ्रेड पर होंगे, और आप यूआई तत्वों आदि तक पहुंच सकते हैं। दूसरे संस्करण में, आप थ्रेड पूल थ्रेड में निष्पादित होंगे, और इसकी आवश्यकता होगी यूआई को अपडेट करने के लिए यूआई थ्रेड पर वापस मार्शल करने के लिए।

ध्यान दें कि आपकी async void विधि लगभग निश्चित रूप से async void नहीं होनी चाहिए। ईवेंट हैंडलर हस्ताक्षरों का अनुपालन करने के लिए आपको केवल async विधि वापसी void बनाना चाहिए। अन्य सभी मामलों में, लौट Task - इस तरह से जब अपने कार्य समाप्त हो गया है फोन करने वाले को देख सकते हैं, अपवाद आदि संभाल

भी ध्यान रखें कि आप asynchrony के लिए HttpClient उपयोग करने की आवश्यकता नहीं है - आप WebClient.DownloadStringTaskAsync बजाय इस्तेमाल कर सकते हैं, तो आपके अंतिम विधि बन सकता है: थ्रेड पूल की क्षमता बढ़ाने और शायद अपने कार्यक्रम अधिक उपयोगकर्ताओं के लिए पैमाने पर करने के लिए अनुमति देता है:

private async Task<string> DownloadHtml(string query) 
{ 
    using (var client = new WebClient()) 
    { 
     try 
     { 
      return await client.DownloadStringTaskAsync(query); 
     } 
     catch (Exception ex) 
     { 
      Logger.Error(msg, ex); 
      return null; 
     } 
    } 
} 
+0

धन्यवाद! हालांकि त्वरित प्रश्न। चलिए पहले कार्यान्वयन में ParseHtml लेते हैं। मैं डाउनलोड एचटीएमएल से प्रचारित कार्य वस्तु कैसे वापस करूँगा? जब मैं इसका मूल्य उपयोग करता हूं तो इसे "माईटाइप" – vondip

+1

@vondip में परिवर्तित कर दिया जाता है: मुझे समझ में नहीं आता कि आपका क्या मतलब है, मुझे डर है। संभवतः एक अलग सवाल के रूप में अधिक विस्तार से पूछें? –

6

सर्वर अनुप्रयोगों के लिए, async अवरुद्ध थ्रेड की संख्या आप मिल गया है कम से कम के बारे में है।

क्लाइंट अनुप्रयोगों के लिए जहां आपको थ्रेड गिनती की देखभाल करने की आवश्यकता नहीं है, async जब आप I/O करते हैं तो अपने यूआई चलने वाले तरल पदार्थ को रखने के लिए अपेक्षाकृत आसान तरीका प्रदान करता है।

यह Task.Run हुड के नीचे से बहुत अलग है।

1

आप केवल async प्रसंस्करण से लाभ होगा अपने बुला धागा यूआई उत्तरदायी रखने की तरह है, ऐसा करने के लिए कुछ सार्थक है या नहीं। यदि आपका कॉलिंग थ्रेड केवल एक कार्य शुरू करता है और कार्य पूरा होने तक प्रतीक्षा करने के अलावा कुछ भी नहीं करता है, तो आपकी प्रक्रिया धीमी गति से चल जाएगी।

आपकी दूसरी कार्यान्वयन एक कार्य शुरू होता है, लेकिन यह कुछ और करने के बिना समाप्त करने के लिए के लिए आप का इंतजार है। इस तरह आप लाभ नहीं उठाएंगे।

आप अपने पर्यावरण का वर्णन नहीं है, लेकिन अगर आप एक यूआई है उत्तरदायी रखना चाहिए कि, तो विधि 1 के कार्यान्वयन ठीक है, कि आपके प्रारंभ() async घोषित नहीं किया गया है और इंतजार नहीं करता है को छोड़कर:

private async Task StartAsync() 
{ 
    foreach (var url in urls) 
    { 
     await ParseHtml(url) 
    } 
} 

आप इस प्रकार एक ईवेंट हैंडलर से कॉल कर सकते हैं:

private async void OnButton1_clicked(object sender, ...) 
{ 
    await StartAsync(); 
} 

नोट: ParseHtml इंतजार से पहले किया जाता है। पिछली पार्स समाप्त होने के बाद अगला एचटीएमएल पार्स किया जाएगा। हालांकि, पार्स एसिंक है, कॉलिंग थ्रेड (यूआई थ्रेड?) उपयोगकर्ता इनपुट के जवाब देने जैसी अन्य चीजें करने में सक्षम होगा।

हालांकि, अपने parseHTML समारोह एक साथ चलाने के लिए सक्षम है अगर निम्न कोड बेहतर होगा, और शायद तेजी से:

private async Task StartAsync() 
{ 
    var tasks = new List<Task>() 
    foreach (var url in urls) 
    { 
     tasks.Add(ParseHtml(url)); 
    } 
    // now you have a sequence of Tasks scheduled to be run, possibly simultaneously. 
    // you can do some other processing here 
    // once you need to be certain that all tasks are finished await Task.WhenAll(...) 
    await Task.WhenAll(tasks); 
    // Task.WhenAls(...) returns a Task, hence you can await for it 
    // the return of the await is a void 
} 
  • आप एक समारोह है कि एक टास्क रिटर्न फोन हैं, तो आप अन्य कर जारी रख सकते हैं कार्य पूरा होने और कार्य के परिणामों का उपयोग करने के लिए कार्य चल रहा है या काम का इंतजार कर रहा है।
  • यदि आप प्रतीक्षा करते हैं, तो आपका कोड बंद हो जाता है, लेकिन आपके कॉलर्स
  • को पूरा करने के लिए अपने कार्य का इंतजार करते समय प्रसंस्करण जारी रखते हैं, यदि आप अपनी प्रक्रिया एसिंक हैं तो आप केवल अपनी प्रक्रिया में प्रतीक्षा कर सकते हैं।
  • async फ़ंक्शंस केवल अन्य async फ़ंक्शंस द्वारा कॉल किया जा सकता है, या टास्क.रुन (() => ...) को कॉल करके या यदि पसंदीदा: Task.Factory.StartNew (() => ...)
  • शून्य के बजाय एक async फ़ंक्शन कार्य
  • TResult के बजाय एक async समारोह वापसी टास्क <TResult>
  • एकमात्र अपवाद ईवेंट हैंडलर है: यह async घोषित करने और शून्य लौट आते हैं।
  • यदि आपको कार्य पूरा करने की आवश्यकता है, तो बस कार्य के लिए प्रतीक्षा करें।
  • प्रतीक्षा की वापसी TResult है।

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

  • कोई संबंधित समस्या नहीं^_^