2013-08-21 23 views
8

बनाना मैंने एसिंक विधियों को पढ़ने की कोशिश की है और अब मैं अपना स्वयं का एसिंक विधि बनाने की कोशिश कर रहा हूं। विधि एक webservice कॉल है जो त्रुटि लॉग की एक सूची देता है। मुझे यकीन नहीं है कि मैं सही ढंग से समझ गया हूं इसलिए मैंने सोचा कि मैं यह देखने के लिए अपना कोड साझा करूंगा कि मुझे कुछ अलग करना चाहिए या नहीं।एक async webservice विधि

मैं चाहता हूं कि कोड करने के लिए कोड GetAllErrorLogs() पर कॉल करके त्रुटि लॉग की सूची लौटाएं, यह एक सिंक्रनाइज़ विधि है। चूंकि सभी त्रुटि लॉग लाने में एक सेकंड लग सकता है, इसलिए मैं GetAllErrorLogs() विधि कहने के बाद अन्य सामान करने का अवसर प्राप्त करना चाहता हूं। कोड यहाँ है।

[WebMethod] 
public async Task<List<ErrorLog>> GetAllErrorLogs() 
{ 
    List<ErrorLog> errorLogs = new List<ErrorLog>(); 

    await System.Threading.Tasks.Task.Run(() => { 
     errorLogs = ErrorLogRepository.GetAllErrorLogs(); 
    }); 


    if (errorLogs == null) 
     return new List<ErrorLog>(); 

    return errorLogs; 
} 

धन्यवाद!

+1

मैं बहुत ज्यादा नहीं लाभ async का उपयोग कर देख पा रहे हैं/सर्वर साइड पर इंतजार है। आप बस एक ही चीज़ के लिए अधिक धागे का उपयोग करें। – I4V

+4

@ I4V: सर्वर पक्ष पर 'async' नाटकीय रूप से * प्रति अनुरोध किए गए धागे की संख्या को कम कर सकता है (यह मानते हुए कि कोड स्वाभाविक रूप से असीमित है और नकली-एसिंक्रोनस नहीं है जैसे' टास्क.रुन')। नतीजतन, एसिंक्रोनस सर्वर 10-100x के क्रम पर अक्सर बेहतर पैमाने पर स्केल करने में सक्षम होते हैं। –

+0

स्टीफन क्लेरी सही है ... मैंने एक माइक्रोसॉफ्ट परिसर में एक प्रशिक्षण पाठ्यक्रम में भाग लिया जहां हमें बताया गया था कि बस आपके सर्वर पर चलने वाले सभी कोड को एसिंक करके, आपको उसी हार्डवेयर के लिए क्षमता में भारी वृद्धि होगी। शुद्ध रूप से, जब कोई विधि किसी उप कॉल से प्रतिक्रिया के लिए प्रतीक्षा कर रही है, तो मुख्य थ्रेड जारी करने और अन्य काम करने के लिए जारी किया जाता है ... यानी अन्य समवर्ती वेब अनुरोधों के साथ सौदा करें। लाभ multitasking है। – GPR

उत्तर

7

मैंने हाल ही में ThatConference पर async on the server side पर एक वार्ता दी, और मैं स्लाइड्स में इस समस्या को संबोधित करता हूं।

सर्वर की तरफ, आप Task.Run और अन्य संरचनाओं के उपयोग से बचना चाहते हैं जो थ्रेड पूल में कतार का काम करते हैं। जितना संभव हो, अनुरोधों को संभालने के लिए थ्रेड पूल थ्रेड उपलब्ध रखें।

तो, आदर्श रूप से आपके भंडार में एसिंक्रोनस विधि GetAllErrorLogsAsync होगी, जो स्वयं ही असीमित होगी। यदि GetAllErrorLogs असीमित नहीं हो सकता है, तो आप इसे सीधे कॉल भी कर सकते हैं (await Task.Run को हटाएं)।

चूंकि सभी त्रुटि लॉग लाने के लिए एक सेकंड लग सकता है, इसलिए मैं GetAllErrorLogs() विधि को कॉल करने के बाद अन्य सामान करने का अवसर प्राप्त करना चाहता हूं।

आप एक GetAllErrorLogsAsync उपलब्ध है, तो यह आसानी से Task.WhenAll का उपयोग किया जा सकता है। हालांकि, अगर GetAllErrorLogs तुल्यकालिक है, तो आप केवल अपने अनुरोध में समानांतर काम करके ऐसा कर सकते हैं (उदा।, Task.Run पर कई कॉल Task.WhenAll के बाद)।

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

+0

उत्तर के लिए धन्यवाद! – Andreas

+0

समांतरता की जटिलताओं यहां और ऑफ-विषय के लिए बहुत लंबी हैं, लेकिन यह ध्यान दिया जाना चाहिए कि समांतरता के खिलाफ चेतावनी यहां पर है। यदि आप किसी वेब सेवा और डेटाबेस कॉल के लिए वेब अनुरोध का इंतजार कर रहे हैं, तो आप I/O प्राप्ति पोर्ट थ्रेड का लाभ उठा रहे हैं जो सुपर सस्ता, ओएस-स्तर हैं, और थ्रेडपूल से धागे नहीं खाते हैं। समांतरता के लिए एक आदर्श परिदृश्य जो उपयोगकर्ता के लिए अनुरोध थ्रेडपूल को ब्लिट्ज किए बिना चीजों को गति देता है। यहां सही जवाब "यहां है" नहीं होगा "ऐसा मत करो।" http://stackoverflow.com/a/539968/176877 –

+0

@ChrisMoschini: मैं * मल्टीथ्रेडिंग/समांतरता * ('टास्क.रुन', 'समांतर', आदि) और * एसिंक्रॉन्सी * (' async', '' के बीच एक अंतर बना देता हूं। प्रतीक्षा करें, आदि), जिनमें से दोनों [समरूपता * के विभिन्न रूप हैं] [https://pbs.twimg.com/media/B63AADfIgAA4jPH.jpg:large)। उन परिभाषाओं के साथ, सर्वर पक्ष पर समांतरता खराब है। –

0

** यह संभावित रूप से गलत है, टिप्पणी या spinoff सवाल HttpContext.Current after an await

तो ErrorLogRepository.GetAllErrorLogs() पर पढ़ने के लिए है नहीं थ्रेड के बारे में इस महान codeproject विस्तृत लेख पाया -साफ, यह अजीब कीड़े और संभावित रूप से अपवाद का कारण बन जाएगा। सुनिश्चित करें कि आपका कोड एसिंक तरीकों पर स्विच करने से पहले बहु-थ्रेडेड ऑपरेशन के लिए तैयार है, यह स्पष्ट रूप से बहुत ही छोटी सलाह है लेकिन अक्सर अनदेखा किया जाता है। उदाहरण के लिए, यदि आप अपनी विधियों में HttpContext.Current का संदर्भ देते हैं, तो आपका कोड एसिंक विधि में मर जाएगा, और कभी-कभी await के बाद भी। कारण यह है कि एसिंक ब्लॉक के भीतर कोड संभावित रूप से एक अलग थ्रेड पर चलाया जाएगा, जिसकी HttpContext.Current थ्रेड-स्टेटिक प्रॉपर्टी तक पहुंच नहीं होगी, और await दो तरीकों से संकलित हो जाएगी। await से पहले सभी कोड एक थ्रेड पर चलाए जाते हैं, और फिर निरंतरता के रूप में एक प्रतीक्षा कीवर्ड के बाद कोड को कॉल करते हैं, लेकिन संभावित रूप से अभी तक एक और धागा पर। तो कभी-कभी आपका कोड एसिंक ब्लॉक में भी काम करेगा, केवल एसिंक के "बाहर" होने के बाद अप्रत्याशित रूप से चकित हो जाएगा, जो आपको लगता है कि आपके कोड का एक तुल्यकालिक हिस्सा है (लेकिन हकीकत में await कीवर्ड के बाद सबकुछ पहले ही गारंटी नहीं है मूल धागा होने के लिए)।

+0

इस उत्तर में बहुत सारी गलत जानकारी है। 'UnobservedTaskException' की आवश्यकता नहीं है ('प्रतीक्षा करें' वेबएपीआई विधि के माध्यम से' GetAllErrorLogs' से किसी भी अपवाद को सही ढंग से प्रसारित करेगा)। 'HttpContext.Current' डिफ़ॉल्ट रूप से एक async अनुरोध को संभालने वाले सभी थ्रेडों के लिए उचित रूप से प्रचारित किया जाता है (यानी,' वापसी त्रुटि लॉग 'पंक्ति में पूरी तरह मान्य' HttpContext.Current') है। –

+0

आप प्रतीक्षा करने के बारे में सही हैं, मैंने उस हिस्से को गलत तरीके से पढ़ा। यह केवल कार्य की स्थिति में प्रचारित नहीं किया जाएगा। रून आग के रूप में इस्तेमाल किया जा रहा है और भूल जाओ। हालांकि, HttpContext.Current प्रतीक्षा के बाद निश्चित रूप से मान्य नहीं होगा जब तक कि वेबएपीआई ने डिफ़ॉल्ट सिंक्रनाइज़ेशन संदर्भ व्यवहार को ओवरराइड नहीं किया हो। – welegan

+1

वेबएपीआई सिंक्रनाइज़ेशन संदर्भ प्रदान नहीं करता है, लेकिन एएसपी.नेट करता है। इसलिए 'प्रतीक्षा करें 'के बाद' HttpContext.Current' पूरी तरह मान्य है। –

0

यहाँ हैंडलिंग Async अपवाद भी बहुत बहुत महत्वपूर्ण .. हालांकि यह एक खिड़कियों सांत्वना अनुप्रयोग के लिए है, एक ही सिद्धांतों को लागू करना चाहिए कुछ उत्पादन कोड है ...

using System.Web.Http; 
using AysncTask = System.Threading.Tasks.Task; 

public class myController : ApiControllerBase 
{ 
     [HttpPut] 
     [Route("api/cleardata/{id}/{requestId}/")] 
     public async AysncTask ClearData(Guid id, Guid requestId) 
     { 
      try 
      { 
       await AysncTask.Run(() => DoClearData(id, requestId)); 
      } 
      catch (Exception ex) 
      { 
       throw new Exception("Exception in myController.ClearData", ex); 
      } 
     } 
} 
0

स्रोत: https://blogs.msdn.microsoft.com/ptorr/2014/12/10/async-exceptions-in-c/

using System; 
    using System.Runtime.CompilerServices; 
    using System.Threading; 
    using System.Threading.Tasks; 

    namespace AsyncAndExceptions 
    { 
class Program 
{ 
    static void Main(string[] args) 
    { 
    AppDomain.CurrentDomain.UnhandledException += (s, e) => Log("*** Crash! ***", "UnhandledException"); 
    TaskScheduler.UnobservedTaskException += (s, e) => Log("*** Crash! ***", "UnobservedTaskException"); 

    RunTests(); 

    // Let async tasks complete... 
    Thread.Sleep(500); 
    GC.Collect(3, GCCollectionMode.Forced, true); 
    } 

    private static async Task RunTests() 
    { 
    try 
    { 
     // crash 
     // _1_VoidNoWait(); 

     // crash 
     // _2_AsyncVoidAwait(); 

     // OK 
     // _3_AsyncVoidAwaitWithTry(); 

     // crash - no await 
     // _4_TaskNoWait(); 

     // crash - no await 
     // _5_TaskAwait(); 

     // OK 
     // await _4_TaskNoWait(); 

     // OK 
     // await _5_TaskAwait(); 
    } 
    catch (Exception ex) { Log("Exception handled OK"); } 

    // crash - no try 
    // await _4_TaskNoWait(); 

    // crash - no try 
    // await _5_TaskAwait(); 
    } 

    // Unsafe 
    static void _1_VoidNoWait() 
    { 
    ThrowAsync(); 
    } 

    // Unsafe 
    static async void _2_AsyncVoidAwait() 
    { 
    await ThrowAsync(); 
    } 

    // Safe 
    static async void _3_AsyncVoidAwaitWithTry() 
    { 
    try { await ThrowAsync(); } 
    catch (Exception ex) { Log("Exception handled OK"); } 
    } 

    // Safe only if caller uses await (or Result) inside a try 
    static Task _4_TaskNoWait() 
    { 
    return ThrowAsync(); 
    } 

    // Safe only if caller uses await (or Result) inside a try 
    static async Task _5_TaskAwait() 
    { 
    await ThrowAsync(); 
    } 

    // Helper that sets an exception asnychronously 
    static Task ThrowAsync() 
    { 
    TaskCompletionSource tcs = new TaskCompletionSource(); 
    ThreadPool.QueueUserWorkItem(_ => tcs.SetException(new Exception("ThrowAsync"))); 
    return tcs.Task; 
    } 
    internal static void Log(string message, [CallerMemberName] string caller = "") 
    { 
    Console.WriteLine("{0}: {1}", caller, message); 
    } 
} 

}

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