पूरा करने के लिए async विधि की प्रतीक्षा कैसे करें?


138

मैं एक WinForms एप्लिकेशन लिख रहा हूं जो USB HID क्लास डिवाइस में डेटा ट्रांसफर करता है। मेरा एप्लिकेशन उत्कृष्ट जेनेरिक HID लाइब्रेरी v6.0 का उपयोग करता है जो यहां पाया जा सकता है । संक्षेप में, जब मुझे डिवाइस पर डेटा लिखने की आवश्यकता होती है, तो यह वह कोड होता है जिसे कॉल किया जाता है:

private async void RequestToSendOutputReport(List<byte[]> byteArrays)
{
    foreach (byte[] b in byteArrays)
    {
        while (condition)
        {
            // we'll typically execute this code many times until the condition is no longer met
            Task t = SendOutputReportViaInterruptTransfer();
            await t;
        }

        // read some data from device; we need to wait for this to return
        RequestToGetInputReport();
    }
}

जब मेरा कोड लूप से बाहर निकल जाता है, तो मुझे डिवाइस से कुछ डेटा पढ़ने की आवश्यकता होती है। हालाँकि, डिवाइस अभी प्रतिक्रिया देने में सक्षम नहीं है इसलिए मुझे जारी रखने से पहले इस कॉल के लौटने की प्रतीक्षा करनी होगी। जैसा कि यह वर्तमान में मौजूद है, RequestToGetInputReport () इस तरह से घोषित किया गया है:

private async void RequestToGetInputReport()
{
    // lots of code prior to this
    int bytesRead = await GetInputReportViaInterruptTransfer();
}

इसके लायक क्या है, GetInputReportViaInterruptTransfer () के लिए घोषणा इस प्रकार है:

internal async Task<int> GetInputReportViaInterruptTransfer()

दुर्भाग्य से, मैं .NET 4.5 में नई async / प्रतीक्षा प्रौद्योगिकी के कामकाज से बहुत परिचित नहीं हूं। मैंने थोड़ी देर पहले वाट्सएप कीवर्ड के बारे में पढ़ा और इससे मुझे यह आभास हुआ कि RequestToGetInputReport () के अंदर GetInputReportViaInterruptTransfer () के लिए कॉल प्रतीक्षा करेगा (और हो सकता है?) लेकिन यह RequestToGetInputReport () के लिए कॉल की तरह प्रतीत नहीं होता है? स्वयं प्रतीक्षा कर रहा है क्योंकि मैं लगभग तुरंत लूप में फिर से प्रवेश कर रहा हूं?

क्या कोई भी मेरे द्वारा देखे जा रहे व्यवहार को स्पष्ट कर सकता है?

जवाबों:


131

से बचें async voidTaskइसके बजाय अपने तरीके लौटाएं void। फिर आप awaitउन्हें कर सकते हैं।

ऐशे ही:

private async Task RequestToSendOutputReport(List<byte[]> byteArrays)
{
    foreach (byte[] b in byteArrays)
    {
        while (condition)
        {
            // we'll typically execute this code many times until the condition is no longer met
            Task t = SendOutputReportViaInterruptTransfer();
            await t;
        }

        // read some data from device; we need to wait for this to return
        await RequestToGetInputReport();
    }
}

private async Task RequestToGetInputReport()
{
    // lots of code prior to this
    int bytesRead = await GetInputReportViaInterruptTransfer();
}

1
बहुत बढिया आपको धन्यवाद। मैं इसी तरह के मुद्दे पर अपना सिर खुजला रहा था और अंतर यह था कि जैसा आपने कहा था वैसा ही बदल voidजाना Taskचाहिए।
जेरेमी

8
यह एक मामूली बात है, लेकिन अधिवेशन का पालन करने के लिए दोनों विधियों में Async को उनके नाम में जोड़ा जाना चाहिए, जैसे RequestToGetInputReportAsync ()
tymtam

6
और क्या होगा अगर कॉलर मेन फंक्शन है?
सहजीवन

14
@ सिम्बियन्ट: फिर उपयोग करेंGetAwaiter().GetResult()
स्टीफन

4
@AhmedSalah Taskविधि के निष्पादन का प्रतिनिधित्व करता है - इसलिए returnमूल्यों को रखा जाता है Task.Result, और अपवादों को रखा जाता है Task.Exception। साथ void, संकलक कहीं जगह अपवाद है, इसलिए वे सिर्फ एक थ्रेड पूल धागे पर फिर से उठाया जाता है है।
स्टीफन क्ली

229

सबसे महत्वपूर्ण बात यह के बारे में जानना asyncऔर awaitवह यह है कि await यह नहीं है पूरा करने के लिए संबंधित कॉल के लिए प्रतीक्षा करें। क्या awaitकरता है आपरेशन के परिणाम वापस जाने के लिए तुरंत और तालमेल के है आपरेशन पहले से ही पूरा कर लिया है, तो या, यदि यह नहीं है, के शेष निष्पादित करने के लिए एक निरंतरता शेड्यूल करने के लिए asyncविधि और उसके बाद फोन करने वाले के लिए नियंत्रण वापस जाने के लिए। जब एसिंक्रोनस ऑपरेशन पूरा हो जाता है, तो निर्धारित समय पूरा हो जाएगा।

आपके प्रश्न के शीर्षक में विशिष्ट प्रश्न का उत्तर एक asyncविधि के रिटर्न वैल्यू पर ब्लॉक करना है (जो कि एक प्रकार का होना चाहिए ) Taskया Task<T>एक उपयुक्त Waitविधि को कॉल करके :

public static async Task<Foo> GetFooAsync()
{
    // Start asynchronous operation(s) and return associated task.
    ...
}

public static Foo CallGetFooAsyncAndWaitOnResult()
{
    var task = GetFooAsync();
    task.Wait(); // Blocks current thread until GetFooAsync task completes
                 // For pedagogical use only: in general, don't do this!
    var result = task.Result;
    return result;
}

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

"प्रतीक्षा" पर जवाब कॉल के पूरा होने की प्रतीक्षा नहीं करता है , इन खोजशब्दों के कई, अधिक विस्तृत, स्पष्टीकरण हैं।

इस बीच, @ स्टेफेन क्लीरी के मार्गदर्शन के बारे में async voidरखती है। Http://www.tonicodes.net/blog/why-you-should-almost-never-write-void-asynchronous-methods/ और https://jaylee.org/archive/ पर अन्य अच्छे स्पष्टीकरण क्यों मिल सकते हैं 2012/07/08 / सी तेज async-सुझावों और चाल-भाग-2-async-void.html


18
मुझे await"अतुल्यकालिक प्रतीक्षा" के रूप में सोचने (और बात करने) में उपयोगी लगता है - अर्थात, यह विधि को अवरुद्ध करता है (यदि आवश्यक हो) लेकिन धागा नहीं । तो यह RequestToSendOutputReport"प्रतीक्षा" के बारे में बात करने के लिए समझ में आता है, RequestToGetInputReportभले ही यह एक अवरुद्ध प्रतीक्षा नहीं है ।
स्टीफन क्ली

@ रिचर्ड कुक - अतिरिक्त स्पष्टीकरण के लिए बहुत बहुत धन्यवाद!
bmt22033

10
यह स्वीकृत उत्तर होना चाहिए, क्योंकि यह अधिक स्पष्ट रूप से वास्तविक प्रश्न का उत्तर देता है (अर्थात async विधि पर थ्रेड-वार ब्लॉक कैसे करें)।
सीएसवन

जब तक कार्य पूरा नहीं हो जाता, तब तक सर्वोत्तम समाधान प्रतीक्षा करना है कि async है। परिणाम। Task.Run (async () => {रिटर्न का इंतजार करें आपका Method ();}) परिणाम)
राम चितला

70

कार्य पूरा होने तक AsynMethod प्रतीक्षा करने के लिए सबसे अच्छा समाधान

var result = Task.Run(async() => await yourAsyncMethod()).Result;

15
या यह आपके async "void" के लिए: Task.Run (async () => {yourAsyncModod ();}) प्रतीक्षा करें) ()।
जीरन हर्निक

1
आपके ओवरऑन मिक्सथोड () के परिणामस्वरूप इसका क्या लाभ है?
जस्टिन जे स्टार्क

1
बस। एक्सेस संपत्ति वास्तव में तब तक इंतजार नहीं करती है जब तक कि कार्य निष्पादित नहीं हो जाता है। वास्तव में, मेरा मानना ​​है कि यह एक अपवाद फेंकता है अगर यह एक कार्य पूरा होने से पहले कहा जाता है। मुझे लगता है कि इसे टास्क में लपेटने का फायदा। रॉन () कॉल है, क्योंकि रिचर्ड कुक नीचे उल्लेख करते हैं, "वेट" वास्तव में किसी कार्य के पूरा होने का इंतजार नहीं करता है, लेकिन .Wait () कॉल का उपयोग करके आपके पूरे थ्रेड पूल को ब्लॉक कर दिया जाता है। । यह आपको (सिंक्रोनाइज़) एक अलग थ्रेड पर एक async विधि चलाने की अनुमति देता है। थोड़ा भ्रमित, लेकिन वहाँ यह है।
लुकास लेब्लांक

परिणाम में अच्छा फेंकना, बस मुझे क्या चाहिए
गेरी

क्विक रिमाइंडर ECMA7 फीचर लाइक एसिंक्स () या पूर्व ECMA7 वातावरण में अभ्यस्त काम का इंतजार नहीं करता।
Mbotet

0

यहाँ एक ध्वज का उपयोग कर एक समाधान है:

//outside your event or method, but inside your class
private bool IsExecuted = false;

private async Task MethodA()
{

//Do Stuff Here

IsExecuted = true;
}

.
.
.

//Inside your event or method

{
await MethodA();

while (!isExecuted) Thread.Sleep(200); // <-------

await MethodB();
}

-1

कार्य पूरा होने तक प्रतीक्षा करने के लिए बस प्रतीक्षा () करें

GetInputReportViaInterruptTransfer().Wait();


यह वर्तमान थ्रेड को ब्लॉक करता है। तो यह आमतौर पर एक बुरी बात है।
शुद्ध.क्रोम

-4

वास्तव में IAsyncAction को लौटाने वाले कार्यों के लिए मुझे यह अधिक उपयोगी लगा।

            var task = asyncFunction();
            while (task.Status == AsyncStatus.Completed) ;

-5

निम्नलिखित स्निपेट कॉलर को लौटने से पहले प्रतीक्षित विधि को सुनिश्चित करने का एक तरीका दिखाता है। फिर भी, मैं यह नहीं कहूंगा कि यह अच्छा अभ्यास है। यदि आप अन्यथा सोचते हैं तो कृपया मेरे उत्तर को स्पष्टीकरण के साथ संपादित करें।

public async Task AnAsyncMethodThatCompletes()
{
    await SomeAsyncMethod();
    DoSomeMoreStuff();
    await Task.Factory.StartNew(() => { }); // <-- This line here, at the end
}

await AnAsyncMethodThatCompletes();
Console.WriteLine("AnAsyncMethodThatCompletes() completed.")

डाउनवोटर्स, समझाने की देखभाल, जैसे मैंने उत्तर में पूछा था? क्योंकि यह उतना ही अच्छा काम करता है, जितना मैं जानता हूँ ...
जेरेट

3
समस्या यह है कि एक ही रास्ता आप क्या कर सकते हैं await+ Console.WriteLineयह एक बनने से है Taskजो दोनों के बीच नियंत्रण देता है,। इसलिए आपका 'समाधान' अंततः एक उपज देगा Task<T>, जो समस्या को संबोधित नहीं करता है। ऐसा करने से एक Task.Waitहोगा वास्तव में (गतिरोध संभावनाओं आदि के साथ) प्रोसेसिंग रोक देंगे। दूसरे शब्दों में, awaitवास्तव में इंतजार नहीं करता है, यह बस एक में दो अतुल्यकालिक निष्पादन योग्य भागों को जोड़ता है Task(जो कोई देख सकता है या इंतजार कर सकता है)
रूबेन बार्टेलिंक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.