2012-10-24 19 views
52

इस पर विचार करें,का इंतजार नहीं कर सकते async लैम्ब्डा

Task task = new Task (async() =>{ 
    await TaskEx.Delay(1000); 
}); 
task.Start(); 
task.Wait(); 

कॉल task.Wait() कार्य पूरा होने और अगली पंक्ति तुरंत क्रियान्वित किया जाता है के लिए इंतजार नहीं है, लेकिन अगर मैं एक में async लैम्ब्डा अभिव्यक्ति लपेट विधि कॉल, कोड अपेक्षित के रूप में काम करता है।

private static async Task AwaitableMethod() 
{ 
    await TaskEx.Delay(1000);  
} 

तो (svick से अद्यतन अनुसार टिप्पणी)

await AwaitableMethod(); 
+0

में 'आप वास्तव में लौटने और प्रतीक्षा बुला कार्य .Delay से लौटे पर कर रहे हैं AwaitableMethod'() विधि (मुझे लगता है कि यह एक 'कार्य' देता है)। Async lambda में आप कॉल कर रहे हैं 'कार्य कार्य' पर प्रतीक्षा करें। लेकिन फिर भी, मुझे कोई स्पष्टीकरण नहीं है। –

+1

आपको 'प्रतीक्षा करें' 'के साथ' प्रतीक्षा 'मिश्रण के बारे में बहुत सावधान रहना चाहिए। कई मामलों में, जो डेडलॉक्स का कारण बन सकता है। – svick

+0

@ एसविक ने एक प्रतीक्षा [उदाहरण] (http://stackoverflow.com/a/11179035/815938) 'प्रतीक्षा करें 'के साथ' प्रतीक्षा करें' 'प्रतीक्षा करें() ' – kennyzx

उत्तर

69

अपने लैम्ब्डा उदाहरण में, जब आप task.Wait() फोन, आप नए कार्य पर इंतजार कर रहे हैं कि आप का निर्माण किया, देरी नहीं टास्क कि यह रिटर्न ।

Task<Task> task = new Task<Task>(async() => { 
    await Task.Delay(1000); 
}); 
task.Start(); 
task.Wait(); 
task.Result.Wait(); 

आप एक नया कार्य के निर्माण से बच सकते हैं, और बस के बजाय दो से निपटने के लिए एक टास्क है:

Func<Task> task = async() => { 
    await TaskEx.Delay(1000); 
}; 
task().Wait(); 
+8

मैं अत्यधिक पढ़ने की सिफारिश करता हूं [एसिंक लैम्बडास के आसपास गुजरने से बचने के लिए संभावित नुकसान ] (http://blogs.msdn.com/b/pfxteam/archive/2012/02/08/10265476.aspx) और [कार्य। रून बनाम कार्य। फैक्टरी। स्टार्टन्यू] (http://blogs.msdn.com /b/pfxteam/archive/2011/10/24/10229468.aspx)। – Andrew

+1

यदि पहली प्रतीक्षा बहुत सारी प्रसंस्करण के बाद है तो भी आप डबल कार्य चाहते हैं। 'Task.Result.Wait() 'के बजाय आप' कार्य भी कर सकते हैं। अनवर्रप()। प्रतीक्षा करें()' (या 'अनवर्र () 'गैर-शून्य विधियों के लिए)। नया 'टास्क.रुन' विधियां स्वचालित रूप से अनचाहे होती हैं ताकि आप केवल अपेक्षित कार्य पर प्रतीक्षा कर सकें। –

+4

शुरुआत के रूप में, मुझे लगता है कि वे 'async' कीवर्ड के साथ बेहतर काम कर सकते थे; यह बहुत भ्रमित है। – drowa

6
अपने वांछित देरी पाने के लिए आपको भी जिसके परिणामस्वरूप कार्य पर इंतजार करने की आवश्यकता होगी

आपको TaskEx.RunEx का उपयोग करने की आवश्यकता है।

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

वैकल्पिक रूप से, आप कार्य को दो बार इंतजार कर सकते हैं, जिससे आप अपना बाहरी कार्य सही तरीके से बना सकते हैं (जो वर्तमान में आप नहीं हैं)।

वर्तमान कोड (निर्धारित):

Task task = new Task<Task>(async() =>{ 
    await TaskEx.Delay(1000); 
}); 

task.Start(); 
var innerTask = await task; 
await innerTask; 

TaskEx.RunEx का उपयोग करना:

Task task = TaskEx.RunEx(async() =>{ // Framework awaits your lambda internally. 
    await TaskEx.Delay(1000); 
}); 

await task; 
+0

अच्छा स्पष्टीकरण, लेकिन कोड TaskEx.Run काम नहीं करता है, फिर भी एक ही समस्या है। – kennyzx

+2

अरघ, क्षमा करें! मैं .NET 4.5 का उपयोग कर रहा हूं ... मेरा मतलब TaskEx.RunEx लिखना था। अपने हस्ताक्षर की तुलना TaskEx.Run से करें - आप देखेंगे कि यह विशेष रूप से async विधियों को चलाने के लिए क्यों है। –

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