एक शून्य async विधि के लिए प्रतीक्षा करें


155

मैं void asyncअपनी नौकरी खत्म करने के लिए एक विधि का इंतजार कैसे कर सकता हूं ?

उदाहरण के लिए, मेरे पास नीचे की तरह एक फ़ंक्शन है:

async void LoadBlahBlah()
{
    await blah();
    ...
}

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

जवाबों:


234

सबसे अच्छा अभ्यास async voidकेवल फ़ंक्शन को चिह्नित करना है अगर यह आग है और भूल विधि है, यदि आप इंतजार करना चाहते हैं, तो आपको इसे चिह्नित करना चाहिए async Task

मामले में अगर आप अभी भी इंतजार करना चाहते हैं, तो इसे इस तरह से लपेटें await Task.Run(() => blah())


ब्लाह जाहिर तौर पर टास्क लौटा रहा है और हा async हस्ताक्षर क्यों आप बिना इंतजार किए इसे कॉल करेंगे। यहां तक ​​कि वीएस आपको इसके बारे में चेतावनी देगा।
बैटमेसी

8
await Task.Run(() => An_async_void_method_I_can_not_modify_now())
थीमफील्ड

1
await Task.Run(() => blah())भ्रामक है। यह async फ़ंक्शन के पूरा होने का इंतजार नहीं करता है blah, यह कार्य के (तुच्छ) निर्माण का इंतजार करता है, और blah()पूरा होने से पहले ही जारी रहता है ।
जोनाथन लिडबेक

@JonathanLidbeck "कथन गलत होने से ठीक पहले जारी रहता है।" प्रतीक्षा करने का प्रयास करें। Task.un () = (> Thread.Sleep (10_000)) का प्रयास करें, किसी भी लाइन को निष्पादित करने से पहले 10 सेकंड के लिए कार्य का इंतजार किया जाता है
रोहित शर्मा

@RohitSharma, जो आपके उदाहरण के लिए सही है, लेकिन Thread.Sleepasync नहीं है। यह सवाल एक async voidसमारोह की प्रतीक्षा करने के बारे में है , कहते हैंasync void blah() { Task.Delay(10000); }
जोनाथन लिडबेक

59

यदि आप अपने फ़ंक्शन के हस्ताक्षर को बदल सकते हैं async Taskतो आप यहां प्रस्तुत कोड का उपयोग कर सकते हैं


27

उपयोग करने के लिए सबसे अच्छा उपाय है async Task। आपको async voidकई कारणों से बचना चाहिए , जिनमें से एक क्षमता है।

यदि विधि को वापस करने के लिए नहीं बनाया जा सकता है Task(जैसे, यह एक घटना हैंडलर है), तो आप SemaphoreSlimविधि संकेत का उपयोग कर सकते हैं जब यह बाहर निकलने वाला है। एक finallyब्लॉक में ऐसा करने पर विचार करें ।


1

एक AutoResetEvent करते हैं, फ़ंक्शन को कॉल करते हैं और फिर AutoResetEvent पर प्रतीक्षा करते हैं और फिर इसे Async शून्य के अंदर सेट करते हैं जब आप जानते हैं कि यह हो गया है।

आप एक टास्क पर भी इंतजार कर सकते हैं जो आपके शून्य async से लौटता है


1

आपको वास्तव में मैन्युअल रूप से कुछ भी करने की आवश्यकता नहीं है, awaitकीवर्ड blah()रिटर्न तक फ़ंक्शन निष्पादन को रोक देता है।

private async void SomeFunction()
{
     var x = await LoadBlahBlah(); <- Function is not paused
     //rest of the code get's executed even if LoadBlahBlah() is still executing
}

private async Task<T> LoadBlahBlah()
{
     await DoStuff();  <- function is paused
     await DoMoreStuff();
}

Tऑब्जेक्ट blah()रिटर्न का प्रकार है

आप वास्तव में awaitएक voidसमारोह नहीं LoadBlahBlah()कर सकते इसलिए ऐसा नहीं हो सकताvoid


मैं LoadBlahBlah()खत्म करने के लिए इंतजार करना चाहता हूं , न किblah()
एमबीजेड

10
दुर्भाग्य से async शून्य विधियाँ निष्पादन को
रोकती

-1

मुझे पता है कि यह एक पुराना सवाल है, लेकिन यह अभी भी एक समस्या है जिसमें मैं घूमता रहता हूं, और फिर भी यह एक स्पष्ट समाधान नहीं है जब यह async का उपयोग करते समय सही ढंग से करने के लिए / एक async शून्य हस्ताक्षर विधि में प्रतीक्षा कर रहा हो।

हालांकि, मैंने देखा कि .Wit () शून्य विधि के अंदर ठीक से काम कर रहा है।

और चूंकि async शून्य और शून्य में एक ही हस्ताक्षर है, आपको निम्नलिखित कार्य करने की आवश्यकता हो सकती है।

void LoadBlahBlah()
{
    blah().Wait(); //this blocks
}

भ्रामक रूप से पर्याप्त async / प्रतीक्षा अगले कोड पर ब्लॉक नहीं होती है।

async void LoadBlahBlah()
{
    await blah(); //this does not block
}

जब आप अपना कोड हटाते हैं, तो मेरा अनुमान है कि async शून्य एक आंतरिक कार्य (async टास्क की तरह) बनाता है, लेकिन चूंकि हस्ताक्षर उस आंतरिक कार्य को वापस करने का समर्थन नहीं करता है

इसका मतलब यह है कि आंतरिक रूप से async शून्य विधि अभी भी आंतरिक रूप से async विधियों का "इंतजार" करने में सक्षम होगी। लेकिन आंतरिक टास्क पूरा होने पर बाहरी रूप से यह जानने में असमर्थ हैं।

तो मेरा निष्कर्ष यह है कि async शून्य उद्देश्य के रूप में काम कर रहा है, और यदि आपको आंतरिक टास्क से प्रतिक्रिया की आवश्यकता है, तो आपको इसके बजाय async टास्क हस्ताक्षर का उपयोग करने की आवश्यकता है।

उम्मीद है कि मेरा जुआ किसी को भी जवाब की तलाश में है।

संपादित करें: मैंने कुछ उदाहरण कोड बनाए और यह देखने के लिए विघटित किया कि वास्तव में क्या चल रहा है।

static async void Test()
{
    await Task.Delay(5000);
}

static async Task TestAsync()
{
    await Task.Delay(5000);
}

में बदल जाता है (संपादित करें: मुझे पता है कि निकाय कोड यहाँ नहीं है, लेकिन राज्य-कक्षों में है, लेकिन राज्य-कक्ष मूल रूप से समान थे, इसलिए मैंने उन्हें जोड़ने में कोई दिक्कत नहीं की)

private static void Test()
{
    <Test>d__1 stateMachine = new <Test>d__1();
    stateMachine.<>t__builder = AsyncVoidMethodBuilder.Create();
    stateMachine.<>1__state = -1;
    AsyncVoidMethodBuilder <>t__builder = stateMachine.<>t__builder;
    <>t__builder.Start(ref stateMachine);
}
private static Task TestAsync()
{
    <TestAsync>d__2 stateMachine = new <TestAsync>d__2();
    stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
    stateMachine.<>1__state = -1;
    AsyncTaskMethodBuilder <>t__builder = stateMachine.<>t__builder;
    <>t__builder.Start(ref stateMachine);
    return stateMachine.<>t__builder.Task;
}

न तो AsyncVoidMethodBuilder या AsyncTaskMethodBuilder वास्तव में प्रारंभ विधि में कोई भी कोड है जो उन्हें ब्लॉक करने के लिए संकेत देगा, और वे शुरू होने के बाद हमेशा एसिंक्रोनस रूप से चलेंगे।

रिटर्निंग टास्क के बिना, यह जांचने का कोई तरीका नहीं होगा कि यह पूरा हो गया है या नहीं।

जैसा कि अपेक्षित था, यह केवल टास्क रनिंग async शुरू करता है, और फिर यह कोड में जारी रहता है। और Async टास्क, पहले यह कार्य शुरू करता है, और फिर इसे वापस लौटाता है।

इसलिए मुझे लगता है कि मेरा जवाब कभी भी एसिंक्स शून्य का उपयोग करने के लिए नहीं होगा, अगर आपको यह जानना आवश्यक है कि कार्य कब किया जाता है, तो यह है कि async टास्क के लिए क्या है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.