2016-02-16 20 views
9

के साथ संघर्ष मैं async/await के बारे में बहुत कुछ पढ़ता हूं, लेकिन मुझे अभी भी निम्नलिखित स्थिति को समझने में कुछ कमी है।एसिंक/प्रतीक्षा सी #

मेरा सवाल है, क्या मुझे अपने "रैपर" विधियों को DoSomething() में लागू करना चाहिए या DoSomethingAsync() में होना चाहिए।

तो बेहतर क्या है (और क्यों): क्या मैं await रैपर विधियों में उपयोग करता हूं या सीधे कार्य वापस करता हूं?

 public static async void Main() 
     { 
      await DoSomething(); 
      await DoSomethingAsync(); 
     } 

     private static Task DoSomething() 
     { 
      return MyLibrary.DoSomethingAsync(); 
     } 

     private static async Task DoSomethingAsync() 
     { 
      await MyLibrary.DoSomethingAsync().ConfigureAwait(false); 
     } 

     public class MyLibrary 
     { 
      public static async Task DoSomethingAsync() 
      { 
       // Here is some I/O 
      } 
     } 
+0

प्रयास करें जो चाहो कर सकते हैं मेरा पहला उदाहरण के रूप में - http://stackoverflow.com/questions/9208921/async- देखना अधिक जानकारी के लिए ऑन-मेन-विधि-ऑफ-कंसोल-ऐप। – rhughes

+0

यह उत्तर आपके लिए सहायक हो सकता है: http://stackoverflow.com/questions/22808475/how-to-force-execution-to-stop-till-asynchronous-function-is-fully-executed – user3340627

+0

देखें [बीच कोई अंतर "कार्य का इंतजार करो। रुन(); वापसी; "और" वापसी कार्य। रुन() "?] (http://stackoverflow.com/q/21033150/1768303)। सच्चाई के लिए – Noseratio

उत्तर

4

Berin का जवाब अच्छा है, लेकिन स्पष्ट रूप से अपने सवाल है, जो निम्नलिखित उदाहरण है में विशेष मामले का समाधान नहीं करता:

1: टास्क रिटर्निंग सीधे

private static Task DoSomething() 
{ 
    return MyLibrary.DoSomethingAsync(); 
} 

2: प्रतीक्षा कर रहा है कार्य और परिणाम

private static async Task DoSomethingAsync() 
{ 
    await MyLibrary.DoSomethingAsync().ConfigureAwait(false); 
} 

थाई में Task को वापस लौटने और Task की प्रतीक्षा करने और प्रतिक्रिया को वापस करने के बीच एकमात्र अंतर यह है कि - बाद के मामले में - Task की प्रतीक्षा करने वाली विधि के आरंभ, निलंबित और निरंतर प्रबंधन के लिए ढांचे द्वारा एक राज्य मशीन बनाई जानी चाहिए । यह कुछ प्रदर्शन ओवरहेड incurs।

आम तौर पर, यदि आप केवल Task वापस कर सकते हैं और इसे उच्चतम प्रतीक्षा कर सकते हैं, तो आपको चाहिए। अधिकांश मामलों में (लेकिन निश्चित रूप से सभी नहीं) वास्तविक मामलों में, यह संभव नहीं होगा क्योंकि आप लौटने से पहले परिणाम की कुछ प्रसंस्करण करना चाहते हैं (और यह वही है जो एसिंक/प्रतीक्षा आपको प्राप्त करने में मदद करता है)।

+0

आपको यह भी ध्यान रखना चाहिए कि 'async' स्पष्ट रूप से आपके लिए' कार्य 'बनाता है, जबकि एक नियमित विधि को' कार्य 'स्टार्टन्यू() 'को कॉल करने की आवश्यकता होती है, यदि वह' कार्य 'ऑब्जेक्ट को वापस करना चाहता है। –

+0

@BerinLoritsch केवल तभी जब यह वास्तव में एक नया कार्य बनाने का इरादा है - इस मामले में कार्य पहले ही 'MyLibrary' द्वारा प्रदान किया गया है और इसे वापस कर दिया जा सकता है। –

+0

उत्तर के लिए धन्यवाद। क्या आप कार्य विधि का उपयोग नहीं करना चाहिए। FromResult() इसके बजाय कार्य। स्टार्टन्यू() नियमित विधि से कार्य के रूप में लौटने पर? – coalmee

8

Async/Await अभी भी अपेक्षाकृत नया है, लेकिन एपीआई को स्पष्ट करने में मदद करने के लिए कुछ अच्छे अभ्यास हैं।

  • एक विधि ही घोषित करने के रूप में async मतलब है कि यह
  • async पर बाद में await करने की उम्मीद कर रहा है परोक्ष आप के लिए एक Task बनाता है: मूल बातें इस कर रहे हैं।
  • await एक बुकमार्क की तरह है। एप्लिकेशन फिर से शुरू होता है जहां प्रतीक्षा कीवर्ड का उपयोग किया गया था।
  • आप कर सकते हैं नहीं await कुछ भी है कि नहीं IAwaitable (सबसे अधिक एक Task) (citation)

एक आवेदन जहां दोनों अतुल्यकालिक कॉल और तुल्यकालिक कॉल देखते हैं में, हम को अपनाया है एक नामकरण परंपरा है:

  • async कॉल Task या Task<T> पर लौटें और नाम के अंत में Async शब्द जोड़ें।
  • सिंक्रोनस कॉल (डिफ़ॉल्ट) बस किसी भी विधि की तरह काम करता है और कोई विशेष सम्मेलन नहीं होता है।

अक्सर, दो विधियां हो सकती हैं जो एक ही काम करती हैं, लेकिन एक सिंक्रोनस है और दूसरा नहीं। आप या तो इसे दो अलग-अलग तरीकों से लागू कर सकते हैं, या आप एक दूसरे के साथ लपेट सकते हैं। यह वास्तव में आपकी जरूरतों पर निर्भर करता है और आपको अधिक उत्तरदायी एप्लिकेशन देने के लिए क्या जा रहा है।

उपर्युक्त उदाहरण में, एसिंक और सामान्य विधि कॉल को संभालने का उचित तरीका 0 विधियों का खुलासा करने के लिए MyLibrary के लिए होगा। उदाहरण के इस तरह होगा:

public static class MyLibrary 
{ 
    public static void DoSomething() 
    { 
     // do some work 
    } 

    public static async Task DoSomethingAsync() 
    { 
     // do similar work but use async API, 
     // can also simply call DoSomething(). 
    } 
} 

// In another part of code would be called like this: 
public static async Task BiggerMethod() 
{ 
    MyLibrary.DoSomething(); 
    await MyLibrary.DoSomethingAsync(); 
} 

क्या आप से बचने के लिए एक नियमित रूप से विधि के साथ एक async विधि लपेटकर है चाहता हूँ। जैसे ही आप सीधे Task के साथ काम करते हैं, आप async और await के सभी लाभ खो देते हैं और आप उन स्थानों को पेश करते हैं जहां आपका कोड डेडलॉक हो सकता है।

+0

, 'आप किसी भी काम की प्रतीक्षा नहीं कर सकते हैं' कथन अस्पष्ट है :) आप किसी भी 'प्रतीक्षा करने योग्य' का इंतजार कर सकते हैं, जिसे – pkuderov

+0

@pkuderov कार्य नहीं करना है, धन्यवाद। यह वास्तव में कुछ है जो मुझे नहीं पता था। –

0

एक-लाइनर के मामले में कोई अंतर नहीं है। लेकिन at least two-async-liners, जैसे के मामले में:

public static async void Main() 
{ 
    await DoSomething(); 
    await DoSomethingAsync(); 
} 

private static Task DoSomethingTwice() 
{ 
    var do1 = MyLibrary.DoSomethingAsync(); 

    // when you await DoSomethingTwice, next line's reached 
    // when do1 task may not be completed 
    var do2 = MyLibrary.DoSomethingAsync(); 

    // return what??? 
    // how to combine them? 

    // okay, you can do that 
    return Task.WhenAll(do1, do2) 
} 

private static async Task DoSomethingTwiceAsync() 
{ 
    await MyLibrary.DoSomethingAsync().ConfigureAwait(false); 

    // when you await DoSomethingTwiceAsync, next line's reached 
    // when prev-line task is completed 
    await MyLibrary.DoSomethingAsync().ConfigureAwait(false); 
} 

public class MyLibrary 
{ 
    public static async Task DoSomethingAsync() 
    { 
     // Here is some I/O 
    } 
} 

सारांश:

  • आप काम के अनुक्रमिक asyncronous peaces की एक श्रृंखला के रूप में आप विधि व्यवस्थित करने के लिए है, तो: doAsync1() ->doAsync2() ->doAsync3(),

यानी प्रत्येक अगली शांति को पिछले एक के पूर्ण परिणाम की आवश्यकता है, तो आपको प्रत्येक कॉल का इंतजार करना चाहिए:

async Task DoAsync() 
{ 
    await doAsync1(); 
    await doAsync2(); 
    await doAsync3(); 
} 
  • लेकिन आप उपयोग नहीं कर सकते non-async तरीकों में का इंतजार है। तो आप इसे अपने Task DoSomething() शैली में नहीं कर सकते, केवल async Task DoSomethingAsync() के रूप में।
  • कोई asyncronous श्रृंखला - तो आप उपयोग कर `async main` से बचने के लिए ऊपर
+0

यह ध्यान रखना महत्वपूर्ण है कि उपर्युक्त ('DoAsync') केवल तभी उपयुक्त है जब आपको कार्यों को अनुक्रमिक रूप से चलाने की आवश्यकता हो - यदि आप उन्हें समवर्ती होना चाहते हैं तो आपको उन्हें सभी बंद करने की आवश्यकता है और * फिर * प्रतीक्षा करें। –

+0

@ एएनटीपी धन्यवाद! यही वही है जो मेरा मतलब 'एसिंक्रोनस कॉल' की श्रृंखला के रूप में था। शायद मुझे इसके बजाय 'काम के अनुक्रमिक असिंक्रोनस peaces' कहना चाहिए। और आपका दूसरा मामला मेरे पहले उदाहरण में है - विधि 'DoSomethingTwice'। – pkuderov