2016-01-06 12 views
10

मेरे पास 30 उप कंपनियां हैं और हर किसी ने अपनी वेब सेवा (विभिन्न तकनीकों के साथ) लागू की है।कई वेब सेवाओं को कॉल करने का सबसे अच्छा तरीका?

मुझे उन्हें एकत्र करने के लिए एक वेब सेवा लागू करने की आवश्यकता है, उदाहरण के लिए, सभी उप कंपनी वेब सेवाओं के पास GetUserPoint(int nationalCode) नाम के साथ एक वेब विधि है और मुझे अपनी वेब सेवा को लागू करने की आवश्यकता है जो उन सभी को कॉल करेगा और सभी को एकत्र करेगा प्रतिक्रियाएं (उदाहरण के लिए अंक की राशि)।

public abstract class BaseClass 
{ // all same attributes and methods 
    public long GetPoint(int nationalCode); 
} 

उप कंपनियों वेब सेवाओं में से प्रत्येक के लिए, मैं एक वर्ग है कि इस आधार वर्ग विरासत को लागू करने और अपने स्वयं के GetPoint विधि को परिभाषित:

यह मेरा आधार वर्ग है।

public class Company1 
{ 
    //implement own GetPoint method (call a web service). 
} 

public class CompanyN 
{ 
    //implement own GetPoint method (call a web service). 
} 

इतना करने के लिए, यह मेरा वेब विधि है:

 [WebMethod] 
     public long MyCollector(string nationalCode) 
     { 

      BaseClass[] Clients = new BaseClass[] { new Company1(),//... ,new Company1()} 

      long Result = 0; 
      foreach (var item in Clients) 
      { 
       long ResultTemp = item.GetPoint(nationalCode); 
       Result += ResultTemp; 
      } 
     return Result; 
     } 

ठीक है, यह काम करता है, लेकिन यह इतनी धीमी गति से है, क्योंकि हर उप कंपनी वेब सेवा विभिन्न सर्वरों पर होस्ट कर रहा है (इंटरनेट पर)।

मैं इस तरह समानांतर कार्यक्रमों की उपयोग कर सकते हैं:

foreach (var item in Clients) 
    { 
        Tasks.Add(Task.Run(() => 
         { 
         Result.AddRange(item.GetPoint(MasterLogId, mobileNumber));     
        } 
     } 

मुझे लगता है कि समानांतर कार्यक्रमों की (और सूत्रण) क्योंकि मेरे समाधान आईओ बाध्य है, इस समाधान के लिए अच्छा नहीं है (यह कहा जाता समानांतर कार्यक्रमों की !? है) (सीपीयू गहन नहीं)!

कॉल करें हर बाहरी वेब सेवा इतनी धीमी है, क्या मैं सही हूँ? प्रतिक्रिया प्राप्त करने के लिए लंबित कई धागे!

मुझे लगता है कि एसिंक प्रोग्रामिंग सबसे अच्छा तरीका है लेकिन मैं एसिंक प्रोग्रामिंग और समांतर प्रोग्रामिंग के लिए नया हूं।

सबसे अच्छा तरीका क्या है? (समानांतर .foreach - async टीएपी - async एपीएम - async ईएपी-थ्रेडिंग)

कृपया मेरे लिए एक उदाहरण लिखें। तब

public abstract class BaseClass 
{ // all same attributes and methods 
    public abstract long GetPoint(int nationalCode); 

    public async Task<long> GetPointAsync(int nationalCode) 
    { 
     return await GetPoint(nationalCode); 
    } 
} 

, प्रत्येक ग्राहक के कॉल के लिए कार्य एकत्रित करते हैं:

+0

आपको अपनी सभी मूलभूत बातें मिल गईं। यह एक बहुत अच्छी शुरुआत है। 'समानांतर। फॉरएच 'और' थ्रेड 'जैसी समस्या से पीड़ित है' कार्य '।' वे सीपीयू के लिए अच्छे हैं, आईओ-बाध्य काम नहीं। टीएपी निश्चित रूप से लिखने के लिए सबसे आसान है (आप मूल रूप से अपने वर्तमान पाश को रखते हैं, लेकिन आईओ सामान "थ्रेडलेस" और बहुत स्केलेबल बन जाता है)। एपीएम और ईएपी आसानी से टीएपी ('टास्क.फैक्टरी.फ्रॉमएसिंक' के माध्यम से एपीएम के लिए और 'टास्क कॉम्प्लेशनसोर्स ' ईएपी के लिए परिवर्तनीय हैं), ताकि आप टीएपी के साथ जा सकें और एपीएम और ईएपी कॉल में प्लग कर सकें यदि आपका मौजूदा एपीआई प्रदान करता है। –

उत्तर

7

किसी ऐसे व्यक्ति को देखना ताज़ा है जिसने अपना होमवर्क किया है।

पहली चीजें पहले .NET 4 के रूप में (और आज भी यह मामला बहुत अधिक है) टीएपी .NET में एसिंक वर्कफ़्लो के लिए पसंदीदा तकनीक है। कार्य आसानी से composable हैं, और आपके वेब सेवा कॉल समानांतर करने के लिए यदि वे सच Task<T>-वापसी एपीआई प्रदान करते हैं तो एक हवा है।अभी के लिए आपने इसे Task.Run के साथ "फिक्र किया" है, और समय के लिए यह आपके उद्देश्यों के लिए बहुत अच्छा हो सकता है। निश्चित रूप से, आपके थ्रेड पूल धागे बहुत समय अवरुद्ध करेंगे, लेकिन यदि सर्वर लोड बहुत अधिक नहीं है तो आप इसके साथ बहुत दूर हो सकते हैं भले ही यह आदर्श काम न हो।

आपको बस अपने कोड में एक संभावित दौड़ स्थिति (अंत में उस पर अधिक) को ठीक करने की आवश्यकता है।

यदि आप सर्वोत्तम प्रथाओं का पालन करना चाहते हैं, तो आप सही टीएपी के साथ जाते हैं। यदि आपके एपीआई Task-बॉक्स से बाहर की विधियों को प्रदान करते हैं, तो यह आसान है। यदि नहीं, तो यह एपीएम और ईएपी के रूप में खेल खत्म नहीं हो सकता है आसानी से टीएपी में परिवर्तित किया जा सकता है। एमएसडीएन संदर्भ: https://msdn.microsoft.com/en-us/library/hh873178(v=vs.110).aspx

मैं यहां कुछ रूपांतरण उदाहरण भी शामिल करूंगा।

एपीएम (एक और तो सवाल से लिया गया):

MessageQueue एक ReceiveAsync विधि प्रदान नहीं करता है, लेकिन हम इसे Task.Factory.FromAsync के माध्यम से गेंद को खेलने का प्राप्त कर सकते हैं:

public static Task<Message> ReceiveAsync(this MessageQueue messageQueue) 
{ 
    return Task.Factory.FromAsync(messageQueue.BeginReceive(), messageQueue.EndPeek); 
} 

... 

Message message = await messageQueue.ReceiveAsync().ConfigureAwait(false); 

अपने वेब सेवा प्रॉक्सी हैं BeginXXX/EndXXX विधियां हैं, यह जाने का तरीका है।

ईएपी

मान लें आप एक पुराने वेब सेवा प्रॉक्सी SoapHttpClientProtocol से ली गई है, केवल घटना आधारित async तरीकों के साथ की है। आप इस प्रकार का दोहन करने के लिए उन्हें परिवर्तित कर सकते हैं:

public Task<long> GetPointAsyncTask(this PointWebService webService, int nationalCode) 
{ 
    TaskCompletionSource<long> tcs = new TaskCompletionSource<long>(); 

    webService.GetPointAsyncCompleted += (s, e) => 
    { 
     if (e.Cancelled) 
     { 
      tcs.SetCanceled(); 
     } 
     else if (e.Error != null) 
     { 
      tcs.SetException(e.Error); 
     } 
     else 
     { 
      tcs.SetResult(e.Result); 
     } 
    }; 

    webService.GetPointAsync(nationalCode); 

    return tcs.Task; 
} 

... 

using (PointWebService service = new PointWebService()) 
{ 
    long point = await service.GetPointAsyncTask(123).ConfigureAwait(false); 
} 

दौड़ से बचना जब परिणाम

के साथ संबंध है समानांतर परिणाम के योग के लिए योग, अपने नल पाश कोड है लगभग सही है, लेकिन आप परिवर्तनशील से बचने की जरूरत आपके Task निकायों के अंदर साझा स्थिति क्योंकि वे समानांतर में निष्पादित होंगे। आपके मामले में साझा राज्य Result है - जो किसी प्रकार का संग्रह है। यदि यह संग्रह थ्रेड-सुरक्षित नहीं है (यानी यदि यह एक साधारण List<long> है), तो आपके पास दौड़ की स्थिति है और आपको Add (पर अपवाद और/या गिराए गए परिणाम मिल सकते हैं, मुझे लगता है कि आपके कोड में AddRange एक टाइपो था, लेकिन यदि नहीं - उपर्युक्त अभी भी लागू होता है)।

एक साधारण async के अनुकूल है फिर से लिखने कि आपके दौड़ ठीक करता है इस प्रकार दिखाई देगा:

List<Task<long>> tasks = new List<Task<long>>(); 

foreach (BaseClass item in Clients) { 
    tasks.Add(item.GetPointAsync(MasterLogId, mobileNumber));     
} 

long[] results = await Task.WhenAll(tasks).ConfigureAwait(false); 

आप आलसी हो सकता है और अब के लिए Task.Run समाधान के साथ छड़ी का फैसला करते हैं, सही संस्करण इस तरह दिखेगा:

List<Task<long>> tasks = new List<Task<long>>(); 

foreach (BaseClass item in Clients) 
{ 
    Task<long> dodgyThreadPoolTask = Task.Run(
     () => item.GetPoint(MasterLogId, mobileNumber) 
    ); 

    tasks.Add(dodgyThreadPoolTask);     
} 

long[] results = await Task.WhenAll(tasks).ConfigureAwait(false); 
2

आप GetPoint का एक async संस्करण बना सकते हैं। उसके बाद, Task.WhenAll का उपयोग करके सभी कार्यों को निष्पादित करें। यह उन सभी को समानांतर में निष्पादित करेगा।

var tasks = Clients.Select(x => x.GetPointAsync(nationalCode)); 
long[] results = await Task.WhenAll(tasks); 

आप को समेकित करना विधि async बनाने के लिए नहीं करना चाहते हैं, तो आप .Result बुला के बजाय का इंतजार कर, करके परिणामों को एकत्र कर सकते हैं: इसके अलावा, के रूप में किरिल से कहा, आप प्रत्येक कार्य के परिणाम का इंतजार कर सकते हैं इसलिए:

long[] results = Task.WhenAll(tasks).Result; 
+1

मेरा मतलब था 'var results = कार्य का इंतजार करना। जब सभी (कार्य);' - क्षमा करें, स्पष्ट होना चाहिए था। –

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

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