2014-05-19 6 views
7

निम्नलिखित कोड को देखते हुए, यह ठीकasync/awaitParallel.ForEach के अंदर करने के लिए है?क्या कुछ .NET समानांतर के लिए कुछ async/प्रतीक्षा करना ठीक है। फॉरएच() कोड?

उदाहरण के लिए।

Parallel.ForEach(names, name => 
{ 
    // Do some stuff... 

    var foo = await GetStuffFrom3rdPartyAsync(name); 

    // Do some more stuff, with the foo. 
}); 

या क्या कुछ गॉचा है कि मुझे इसके बारे में जागरूक होने की आवश्यकता है?

संपादित करें: यह संकलित नहीं है, बीटीडब्ल्यू। बस Pseduo- कोड .. जोर से सोच रहा है।

+0

कि संकलित करता है? –

उत्तर

2

जैसा कि @ श्रीराम सक्थिवेल द्वारा इंगित किया गया है, Parallel.ForEach का उपयोग एसिंक्रोनस लैम्बडास के साथ करने में कुछ समस्याएं हैं। स्टीवन टब का ForEachASync बराबर कर सकता है। उन्होंने कहा कि यह here बारे में बात करती है, लेकिन यहां कोड है:

public static class Extensions 
{ 
    public static Task ForEachAsync<T>(this IEnumerable<T> source, int dop, Func<T, Task> body) 
    { 
     return Task.WhenAll(
      from partition in Partitioner.Create(source).GetPartitions(dop) 
      select Task.Run(async delegate { 
               using (partition) while (partition.MoveNext()) await body(partition.Current); 
      })); 
    } 
} 

यह एक लोड संतुलन विभाजक (doco) बनाने के लिए Partitioner वर्ग का उपयोग करता है, और आप कितने धागे आप dop पैरामीटर के साथ चलाना चाहते हैं निर्दिष्ट कर सकते हैं । इसके बीच अंतर और Parallel.ForEach के बीच अंतर देखने के लिए। निम्नलिखित कोड आज़माएं।

class Program 
    { 
     public static async Task GetStuffParallelForEach() 
     { 
      var data = Enumerable.Range(1, 10); 
      Parallel.ForEach(data, async i => 
      { 
       await Task.Delay(1000 * i); 
       Console.WriteLine(i); 
      }); 
     } 

     public static async Task GetStuffForEachAsync() 
     { 
      var data = Enumerable.Range(1, 10); 
      await data.ForEachAsync(5, async i => 
      { 
       await Task.Delay(1000 * i); 
       Console.WriteLine(i); 
      }); 

     } 

     static void Main(string[] args) 
     { 
      //GetStuffParallelForEach().Wait(); // Finished printed before work is complete 
      GetStuffForEachAsync().Wait(); // Finished printed after all work is done 
      Console.WriteLine("Finished"); 
      Console.ReadLine(); 
     } 

अगर आप GetStuffForEachAsync चलाने कार्यक्रम इंतजार कर रहा है सब काम खत्म करने के लिए के लिए। यदि आप GetStuffParallelForEach चलाते हैं, तो कार्य समाप्त होने से पहले Finished पंक्ति मुद्रित की जाएगी।

6

नहीं, के साथ async को गठबंधन करना समझ में नहीं आता है।

private void DoSomething() 
{ 
    var names = Enumerable.Range(0,10).Select(x=> "Somename" + x); 
    Parallel.ForEach(names, async(name) => 
    { 
     await Task.Delay(1000); 
     Console.WriteLine("Name {0} completed",name); 
    }); 
    Console.WriteLine("Parallel ForEach completed"); 
} 

क्या उत्पादन जैसा कि आप उम्मीद करेंगे:

निम्नलिखित उदाहरण पर विचार?

Name Somename3 completed 
Name Somename8 completed 
Name Somename4 completed 
... 
Parallel ForEach completed 

ऐसा नहीं होगा। यह आउटपुट होगा:

Parallel ForEach completed 
Name Somename3 completed 
Name Somename8 completed 
Name Somename4 completed 
... 

क्यों? क्योंकि जब ForEach पहले await हिट करता है तो विधि वास्तव में लौटती है, Parallel.ForEach नहीं जानता कि यह असीमित है और यह पूरा होने के लिए चला गया!एक और धागा नहीं "समानांतर प्रसंस्करण धागा"

Stephen toub addressed this here

+0

ठीक है - तो आप तब क्या सुझाव देंगे? –

+0

@ Pure.Krome आप जिस समस्या को हल करने का प्रयास करते हैं? दिए गए संदर्भ के साथ जवाब देना मुश्किल है। अगर प्रतीक्षा एक विकल्प है तो आप 'टास्क.रुन (async() => कुछ इंतजार कर सकते हैं())। प्रतीक्षा करें(); ' –

4

एक करीबी वैकल्पिक इस हो सकता है पर निरंतरता के रूप में await रन के बाद कोड:

static void ForEach<T>(IEnumerable<T> data, Func<T, Task> func) 
{ 
    var tasks = data.Select(item => 
     Task.Run(() => func(item))); 

    Task.WaitAll(tasks.ToArray()); 
} 

// ... 

ForEach(names, name => GetStuffFrom3rdPartyAsync(name)); 

आदर्श रूप में, आप एक अवरुद्ध उपयोग नहीं करना चाहिए Task.WaitAll की तरह कहते हैं, अगर आप तरीकों की पूरी श्रृंखला कॉल async, "नीचे सभी तरह से" वर्तमान कॉल स्टैक पर बना सकते हैं:

var tasks = data.Select(item => 
    Task.Run(() => func(item))); 

await Task.WhenAll(tasks.ToArray()); 

इसके अलावा, अगर आप किसी भी सीपीयू बाध्य GetStuffFrom3rdPartyAsync अंदर काम नहीं करते हैं, Task.Run बेमानी हो सकता है:

var tasks = data.Select(item => func(item)); 
3

नाम से, मैं यह सोचते हैं रहा हूँ GetStuffFrom3rdPartyAsync है कि मैं/हे बाध्य। Parallel कक्षा विशेष रूप से सीपीयू-बाध्य कोड के लिए है।

अतुल्यकालिक दुनिया में, आप कई कार्य प्रारंभ करें और फिर (अतुल्यकालिक रूप से) Task.WhenAll का उपयोग कर पूरा करने के लिए उन्हें सभी के लिए इंतजार कर सकते हैं। आप एक दृश्य के साथ शुरू कर रहे हैं के बाद से, यह एक अतुल्यकालिक संचालन के लिए शायद परियोजना प्रत्येक तत्व के लिए सबसे आसान है, और फिर उन कार्यों के सभी का इंतजार है:

await Task.WhenAll(names.Select(async name => 
{ 
    // Do some stuff... 
    var foo = await GetStuffFrom3rdPartyAsync(name); 
    // Do some more stuff, with the foo. 
})); 
संबंधित मुद्दे