2016-09-21 13 views
5

में पूरा हो गया है मान लीजिए मैं निम्नलिखित के लिए एक कॉलबैक है।वहाँ जब एक कार्य Task.WhenAll

क्या मांग पर प्रत्येक परिणाम को संभालने का कोई तरीका है?

IEnumerable<Task<TimeSpan>> tasks = //... 
await Task.WhenAll(tasks, result => 
{ 
    // A task has finished. This will get executed. 
    // result is of type TimeSpan 
}); 
+1

हो सकता है कि 'कार्यों [i] .ContinueWith()'? –

उत्तर

4

वहाँ एक रास्ता मांग पर प्रत्येक परिणाम को संभालने के लिए है:

एक प्रतिनिधि/कॉलबैक है कि जब एक कार्य पूरा हो गया है निष्पादित हो जाएगा दर्ज की तरह

?

हाँ, आप WhenAll के बजाय WhenAny का उपयोग करें ... या प्रत्येक कार्य पर ContinueWith कहते हैं।

उदाहरण के लिए, WhenAny दृष्टिकोण के लिए:

ISet<Task<TimeSpan>> tasks = new HashSet<Task<TimeSpan>>(...); 
while (tasks.Count != 0) 
{ 
    var task = await Task.WhenAny(tasks); 
    // Use task here 
    tasks.Remove(task); 
} 

एक और विकल्प आप इस्तेमाल कर सकते हैं, जहां आप कार्य के अनुक्रम जो क्रम में पूरा करता है में कार्यों की मूल अनुक्रम को बदलने नहीं है, लेकिन एक ही परिणाम दे रही है। विवरण this blog post में हैं, लेकिन नतीजा यह है कि आप उपयोग कर सकते है:

foreach (var task in tasks.InCompletionOrder()) 
{ 
    var result = await task; 
    // Use the result 
} 
+0

धन्यवाद!मुझे लगता है कि मैं 'जारी रखें' दृष्टिकोण के साथ जा रहा हूं, क्योंकि यह क्लीनर लगता है और अधिक अर्थात् सही –

+0

@ जोन्स स्केट हमें कुछ प्रतिष्ठा प्राप्त करने देता है :) –

+0

@ मतिससिसेरो: दोनों अर्थात् सही हैं - यह केवल इस पर निर्भर करता है कि क्या समाप्त होता है सबसे सरल। एक अन्य विकल्प के लिए एक लिंक जोड़ना ... –

4

वहाँ एक रास्ता मांग पर प्रत्येक परिणाम को संभालने के लिए है?

एक प्रतिनिधि/कॉलबैक है कि जब एक कार्य

हाँ पूरा हो गया है निष्पादित हो जाएगा दर्ज की तरह

, आपको केवल अपनी एक सा सोच को समायोजित करने के लिए है।

कॉलबैक पंजीकृत करना भूल जाएं (ContinueWith is a dangerous, extremely low-level API)। साथ ही, आपको पूरा होने तक कार्यों को ऑर्डर करने की आवश्यकता नहीं है। इसके बजाय, संचालन (कार्यों) के संदर्भ में अपनी समस्या के बारे में सोचें।

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

यह वास्तव में क्या async/await के लिए है:

private static async Task<TimeSpan> HandleResultAsync(Task<TimeSpan> operation) 
{ 
    var result = await operation; 
    // A task has finished. This will get executed. 
    // result is of type TimeSpan 
    ... 
    return result; // (assuming you want to propagate the result) 
} 

अब, आप अपने मौजूदा संचालन करने के लिए इस उच्च स्तर के आपरेशन लागू करना चाहते हैं। LINQ के Select इस लिए एकदम सही है:

IEnumerable<Task<TimeSpan>> tasks = ... 
IEnumerable<Task<TimeSpan>> higherLevelTasks = tasks.Select(HandleResultAsync); 

TimeSpan[] results = await Task.WhenAll(higherLevelTasks); 
// By the time you get here, all results have been handled individually. 

आप परिणामों के अंतिम संग्रह की जरूरत नहीं है, तो यह आगे सरल किया जा सकता:

private static async Task HandleResultAsync(Task<TimeSpan> operation) 
{ 
    var result = await operation; 
    // A task has finished. This will get executed. 
    // result is of type TimeSpan 
    ... 
} 

IEnumerable<Task<TimeSpan>> tasks = ... 
IEnumerable<Task> higherLevelTasks = tasks.Select(HandleResultAsync); 
await Task.WhenAll(higherLevelTasks); 
+0

मैं LINQ के 'चयन' के उपयोग के द्वारा वास्तव में * आश्चर्यचकित हूं *। यह बिल्कुल सही है! –

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