2012-12-28 14 views
21

मैं async परीक्षण कर रहा हूँ और मैं इस स्थिति यह है कि मैं नहीं समझ सकता पाया में Task.Delay doesn `t काम: क्यों परिणाम हमेशा होता है 0क्यों इस स्थिति

var watch = Stopwatch.StartNew(); 

var t1 = Task.Factory.StartNew(async() => 
{ 
    await Task.Delay(2000); 

    return 2; 
}); 

var t2 = Task.Factory.StartNew(() => 
{ 
    Task.Delay(1000); 

    return 1; 
}); 

await Task.WhenAll(t1, t2); 

var result = watch.ElapsedMilliseconds; 

मैं चाहते हैं समझने के लिए ! 1000, 2000 या दो कार्यों के योग 3000 क्यों नहीं है? Task.WhenAll क्यों नहीं कार्य पूरा करने के लिए प्रतीक्षा करें?

+0

@GrantThomas मैं इसे एक चर के लिए असाइन करने की कोशिश कर रहा हूं लेकिन यह मुझे एक कंपाइलर त्रुटि देता है, मैं यह कैसे कर सकता हूं? – MuriloKunze

+0

@MuriloKunze उस प्रश्न का उत्तर देने के लिए हमें कोड और त्रुटि की रेखा देखने की आवश्यकता होगी। – Servy

+0

मैंने यह कोशिश की: var taskresult = कार्य का इंतजार करें। जब सभी (टी 1, टी 2); लेकिन यह मुझे 'एक अंतर्निहित टाइप किए गए स्थानीय चर के लिए शून्य असाइन नहीं कर सकता' .. – MuriloKunze

उत्तर

41

ठीक है, तो दूसरा दूसरा आसान है, इसलिए चलो इसे संभालें।

दूसरे कार्य के लिए, t2, आप Task.Delay(1000) के परिणाम के साथ कुछ भी नहीं करते हैं। आप await नहीं करते हैं, तो आप Wait इत्यादि नहीं देखते हैं। यह देखते हुए कि विधि async नहीं है, मुझे लगता है कि इसका मतलब है कि आप इसे अवरुद्ध करने के लिए प्रतीक्षा करें। ऐसा करने के लिए आप Delay के अंत में इसे अवरुद्ध करने के लिए कॉल करना चाहते हैं, या बस Thread.Sleep() का उपयोग करें।


पहला काम के लिए, आप तथ्य यह है कि आप var उपयोग कर रहे हैं ने काट लिया जा रहा है। यह स्पष्ट क्या हो रहा है कि आप var का उपयोग नहीं करते जब:

Task<Task<int>> t1 = Task.Factory.StartNew(async() => 
{ 
    await Task.Delay(2000); 

    return 2; 
}); 

आप न केवल एक int की Taskint करने के काम का एक काम पर वापस लौट रहे,। जैसे ही आंतरिक कार्य शुरू हो रहा है, बाहरी कार्य "पूरा" हो जाता है। जब आप WhenAll का उपयोग करते हैं तो आपको बाहरी कार्य समाप्त होने पर परवाह नहीं है, तो आप आंतरिक कार्य समाप्त होने पर ध्यान देते हैं। इसे संभालने के कई तरीके हैं। एक Unwrap का उपयोग करना है।

Task<int> t1 = Task.Factory.StartNew(async() => 
{ 
    await Task.Delay(2000); 

    return 2; 
}).Unwrap(); 

अब आप अपने उम्मीद Task<int> और WhenAll कम से कम 2000 मिलीसेकेंड ले जाएगा, के रूप में उम्मीद की है। तुम भी एक और await कॉल में जोड़ने के एक ही बात करने के लिए कर सकते हैं:

Task<int> t1 = await Task.Factory.StartNew(async() => 
{ 
    await Task.Delay(2000); 

    return 2; 
}); 

svick in a comment ने उल्लेख किया एक और विकल्प सिर्फ Task.Run बजाय StartNew उपयोग करने के लिए किया जाएगा। इस कारण से डिफ़ॉल्ट विकल्प के रूप Task.Run उपयोग करने के लिए यह प्राथमिकता दी जाती है के लिए

Task<int> t1 = Task.Run(async() => 
{ 
    await Task.Delay(2000); 

    return 2; 
}); 

जब आप async lambdas बना रहे हैं: Task.Run तरीकों कि एक Func<Task<T>> लेने के लिए और एक Task<T> लौट सकते हैं और उन्हें स्वचालित रूप से खोलने के लिए के लिए भार के एक विशेष सेट है क्योंकि यह आपके लिए इस मुद्दे को "संभाल" देगा, हालांकि जटिल मामलों के लिए इसके बारे में जागरूक होना सबसे अच्छा है जहां आप Task.Run का उपयोग नहीं कर सकते हैं।


अंत में हम विकल्प है कि आप ऐसा नहीं किया है, जो आप शायद वास्तव में इस मामले में क्या कर रही होना चाहिए करने के लिए आते हैं। चूंकि Task.Delay पहले से ही एक कार्य देता है, इसे पहले स्थान पर StartNew में रखने की आवश्यकता नहीं है। बल्कि एक नेस्टेड कार्य बनाने और Unwrap का उपयोग करने से आप सिर्फ पहली जगह में लपेट नहीं कर सकते हैं:

var t3 = Task.Delay(3000); 
await Task.WhenAll(t1, t2, t3); 

आप वास्तव में सिर्फ यह है कि तुम क्या कर किया जाना चाहिए समय की एक निश्चित राशि के लिए इंतजार करना चाहते हैं।

+0

महान उत्तर –

+0

के लिए +1 अच्छा जवाब :) – MuriloKunze

+4

एक और विकल्प है: 'कार्य.रुन()' का उपयोग करें। यह स्वयं को कार्य को अनचाहे करता है, इसलिए संभवतः 'स्टार्टन्यू()' को 'अनवरप()' के साथ संयुक्त करने से बेहतर विकल्प है। – svick

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

  • कोई संबंधित समस्या नहीं^_^