2016-07-07 11 views
5

में Async कैसे करें मेरे पास एक async विधि है जो किसी सर्वर से एपीआई डेटा प्राप्त करती है। जब मैं अपने स्थानीय मशीन पर एक कंसोल ऐप में यह कोड चलाता हूं, तो यह एसिंक फ़ंक्शन प्रति मिनट में कुछ सौ http कॉल के माध्यम से दबाकर उच्च गति पर प्रदर्शन करता है। जब मैं एक ही कोड को एक Azure WebJob कतार संदेश से ट्रिगर करने के लिए डालता हूं, हालांकि, यह सिंक्रनाइज़ रूप से काम करता प्रतीत होता है और मेरी संख्या क्रॉल होती है - मुझे यकीन है कि मुझे अपने दृष्टिकोण में कुछ आसान याद आ रही है - किसी भी सहायता की सराहना की।Azure WebJob फ़ंक्शन

(1) .. WebJob समारोह है कि कतार के संदेश के लिए सुनता है और संदेश पर प्रक्रिया हो प्राप्त एपीआई की शुरूआत:

public class Functions 
    { 
     // This function will get triggered/executed when a new message is written 
     // on an Azure Queue called queue. 

     public static async Task ProcessQueueMessage ([QueueTrigger("myqueue")] string message, TextWriter log) 
     { 
      var getAPIData = new GetData(); 
      getAPIData.DoIt(message).Wait(); 
      log.WriteLine("*** done: " + message); 
     } 
    } 

(2) वर्ग कि गति से async मोड में बाहर काम करता है नीला ...

class GetData 
    { 
     // wrapper that is called by the message function trigger 
     public async Task DoIt(string MessageFile) 
     { 
      await CallAPI(MessageFile); 
     } 

     public async Task<string> CallAPI(string MessageFile) 
     { 
      /// create a list of sample APIs to call... 
      var apiCallList = new List<string>(); 
      apiCallList.Add("localhost/?q=1"); 
      apiCallList.Add("localhost/?q=2"); 
      apiCallList.Add("localhost/?q=3"); 
      apiCallList.Add("localhost/?q=4"); 
      apiCallList.Add("localhost/?q=5"); 

      // setup httpclient 
      HttpClient client = 
       new HttpClient() { MaxResponseContentBufferSize = 10000000 }; 
      var timeout = new TimeSpan(0, 5, 0); // 5 min timeout 
      client.Timeout = timeout; 

      // create a list of http api get Task... 
      IEnumerable<Task<string>> allResults = apiCallList.Select(str => ProcessURLPageAsync(str, client)); 
      // wait for them all to complete, then move on... 
      await Task.WhenAll(allResults); 

      return allResults.ToString(); 
     } 

     async Task<string> ProcessURLPageAsync(string APIAddressString, HttpClient client) 
     { 
      string page = ""; 
      HttpResponseMessage resX; 

      try 
      { 
       // set the address to call 
       Uri URL = new Uri(APIAddressString); 
       // execute the call 
       resX = await client.GetAsync(URL); 
       page = await resX.Content.ReadAsStringAsync(); 
       string rslt = page; 
       // do something with the api response data 
      } 
      catch (Exception ex) 
      { 
       // log error 
      } 
      return page; 
     } 

    } 
+1

क्या आपने "getAPIData.DoIt (संदेश) को बदलने का प्रयास किया है। प्रतीक्षा करें();" "पाने के लिए getAPIData.DoIt (संदेश);"? –

+1

धन्यवाद जेसन - आपकी और अन्य टिप्पणियों ने मुझे यह काम करने में मदद की। बहुत सराहना की। – qtime67

उत्तर

4

सबसे पहले क्योंकि आपका ट्रिगर फ़ंक्शन async है, तो आपको के बजाय await का उपयोग करना चाहिए। प्रतीक्षा मौजूदा धागे को अवरुद्ध कर देगा।

public static async Task ProcessQueueMessage([QueueTrigger("myqueue")] string message, TextWriter log) 
{ 
    var getAPIData = new GetData(); 
    await getAPIData.DoIt(message); 
    log.WriteLine("*** done: " + message); 
} 

वैसे भी आप documentation

समानांतर निष्पादन

से उपयोगी जानकारी प्राप्त करने के आप अलग अलग कतारों पर सुन अनेक कार्यों का है, तो कर सकते हैं, एसडीके उन में कॉल करेंगे समानांतर संदेश प्राप्त होने पर समानांतर।

वही सत्य है जब एकल कतार के लिए एकाधिक संदेश प्राप्त होते हैं। डिफ़ॉल्ट रूप से, एसडीके को एक समय में 16 कतार संदेशों का एक बैच मिलता है और फ़ंक्शन निष्पादित करता है जो उन्हें समानांतर में संसाधित करता है।The batch size is configurable। जब संसाधित की जा रही संख्या बैच आकार के आधा हो जाती है, तो एसडीके को एक और बैच मिल जाता है और उन संदेशों को संसाधित करना शुरू कर देता है। इसलिए प्रति फ़ंक्शन पर संसाधित समवर्ती संदेशों की अधिकतम संख्या बैच आकार का ढाई गुना है। यह सीमा प्रत्येक फ़ंक्शन पर अलग-अलग लागू होती है जिसमें QueueTrigger विशेषता है।

var config = new JobHostConfiguration(); 
config.Queues.BatchSize = 50; 
var host = new JobHost(config); 
host.RunAndBlock(); 

हालांकि, यह हमेशा बहुत सारे सूत्र एक ही समय में चल रहा है के लिए एक अच्छा विकल्प नहीं है और खराब प्रदर्शन का नेतृत्व कर सकेगी:

यहाँ बैच आकार को कॉन्फ़िगर करने के लिए एक नमूना कोड है।

एक अन्य विकल्प अपने webjob बाहर पैमाने पर करने के है:

कई उदाहरणों

यदि आपका वेब एप्लिकेशन कई उदाहरण पर चलता है, एक सतत WebJob प्रत्येक मशीन पर चलाता है, और प्रत्येक मशीन के लिए इंतजार करेंगे ट्रिगर्स और कार्यों को चलाने का प्रयास करें। WebJobs SDK कतार ट्रिगर स्वचालित रूप से एक फ़ंक्शन को कतार संदेश को कई बार संसाधित करने से रोकता है; कार्यों को बेवकूफ होने के लिए लिखा जाना नहीं है। हालांकि, यदि आप यह सुनिश्चित करना चाहते हैं कि होस्ट वेब ऐप के कई उदाहरण होने पर भी फ़ंक्शन का केवल एक उदाहरण चलता है, तो आप सिंगलटन विशेषता का उपयोग कर सकते हैं।

+0

धन्यवाद थॉमस - "प्रतीक्षा करें getAPIData.DoIt (संदेश);" चाल चल रही है ... मैंने अब उन्हें बेहतर समझने के लिए एसिंक/समरूपता पर 2 एक्स किताबें खरीदी हैं! – qtime67

+0

@ थॉमस मेरा मानना ​​है कि वेबबॉज डॉक्स से "समांतर निष्पादन" और "एकाधिक उदाहरण" उद्धरण लागू होते हैं कि फ़ंक्शन एसिंक हैं या नहीं। उद्धरण इंप्रेशन दे सकते हैं कि उन समांतर प्रसंस्करण लाभों को आगे बढ़ाने के लिए विधियों को एसिंक होना चाहिए। – Matt

+0

@ मैट, आप सही हैं – Thomas

2

इस Webjobs SDK documentation का रीड है - व्यवहार आप की उम्मीद करनी चाहिए की जाती है कि अपनी प्रक्रिया चलाने के लिए और एक समय में एक संदेश पर कार्रवाई करेंगे, लेकिन पैमाने अधिक उदाहरण अपने अनुप्रयोग सेवा के बनाए जाते हैं, तो (होगा)। यदि आपके पास एकाधिक कतार हैं, तो वे समानांतर में ट्रिगर करेंगे।

प्रदर्शन को बेहतर बनाने के लिए, मैंने आपके द्वारा भेजे गए लिंक में कॉन्फ़िगरेशन सेटिंग्स अनुभाग देखें, जो बैच में ट्रिगर किए जा सकने वाले संदेशों की संख्या को संदर्भित करता है।

यदि आप समानांतर में एकाधिक संदेशों को संसाधित करना चाहते हैं, और उदाहरण स्केलिंग पर भरोसा नहीं करना चाहते हैं, तो आपको इसके बजाय थ्रेडिंग का उपयोग करने की आवश्यकता है (async बहु-थ्रेडेड समांतरता के बारे में नहीं है, बल्कि अधिक कुशल उपयोग करना आप जिस थ्रेड का उपयोग कर रहे हैं)। तो आपकी कतार ट्रिगर फ़ंक्शन को कतार से संदेश पढ़ना चाहिए, थ्रेड बनाएं और उस थ्रेड को "आग और भूलें", और फिर ट्रिगर फ़ंक्शन से वापस आएं। यह संदेश को संसाधित के रूप में चिह्नित करेगा, और कतार पर अगले संदेश को संसाधित करने की अनुमति देगा, भले ही सिद्धांत में आप अभी भी पहले की प्रक्रिया कर रहे हों। ध्यान दें कि आपको त्रुटि प्रबंधन के लिए अपना तर्क शामिल करना होगा और यह सुनिश्चित करना होगा कि यदि आपका धागा अपवाद फेंकता है या संदेश को संसाधित नहीं कर सकता है (उदाहरण के लिए इसे एक जहर कतार में डाल दें) तो डेटा खो जाएगा।

दूसरा विकल्प [queuetrigger] विशेषता का उपयोग नहीं करना है, और अपनी आवश्यकताओं के अनुसार संदेशों को जोड़ने और संसाधित करने के लिए सीधे Azure संग्रहण कतार एसडीके एपीआई फ़ंक्शंस का उपयोग करना है।

+0

बहुत धन्यवाद रसेल - इसने मुझे और जानने और चीज़ को ऊपर उठाने और चलाने के लिए निर्देशित किया है। बहुत सराहना की। – qtime67

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