2016-02-01 11 views
5

Sono un po 'confuso su come async/await possa funzionare come parallelo, quindi ho creato un codice di test qui: provo a inviare 6 task che ho simulato con un elenco. ciascuna di queste attività eseguirà 3 altre attività secondarie.Async await e parallel

è possibile copiare/incollare per il test

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Threading; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      //job simulation 
      Func<int, string, Tuple<int, string>> tc = Tuple.Create; 
      var input = new List<Tuple<int, string>>{ 
        tc(6000, "task 1"), 
        tc(5000, "task 2"), 
        tc(1000, "task 3"), 
        tc(1000, "task 4"), 
        tc(1000, "task 5"), 
        tc(1000, "task 6") 
      }; 

      List<Tuple<int, string>> JobsList = new List<Tuple<int, string>>(input); 

      //paralelism atempt 
      List<Task> TaskLauncher = new List<Task>(); 

      Parallel.ForEach<Tuple<int, string>>(JobsList, item => JobDispatcher(item.Item1, item.Item2)); 

      Console.ReadLine(); 
     } 
     public static async Task JobDispatcher(int time , string query) 
     { 
      List<Task> TList = new List<Task>(); 
      Task<string> T1 = SubTask1(time, query); 
      Task<string> T2 = SubTask2(time, query); 
      Task<string> T3 = SubTask3(time, query); 
      TList.Add(T1); 
      TList.Add(T2); 
      TList.Add(T3); 
      Console.WriteLine("{0} Launched ", query); 

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


      Console.WriteLine(T1.Result); 
      Console.WriteLine(T2.Result); 
      Console.WriteLine(T3.Result); 

     } 


     public static async Task<string> SubTask1(int time, string query) 
     { 
      //somework 
      Thread.Sleep(time); 
      return query + "Finshed SubTask1"; 
     } 
     public static async Task<string> SubTask2(int time, string query) 
     { 
      //somework 
      Thread.Sleep(time); 
      return query + "Finshed SubTask2"; 
     } 
     public static async Task<string> SubTask3(int time, string query) 
     { 
      //somework 
      Thread.Sleep(time); 
      return query + "Finshed SubTask3"; 
     } 


    } 
} 

Idealmente al momento del lancio dovrei leggere:

task 1 launched 
task 2 launched 
task 3 launched 
task 4 launched 
task 5 launched 
task 6 launched 

allora a questo punto avere tutte compito di matricola 6 * 3 = 18 filo runing contemporaneamente ma non è quello che succede qui cosa sembra eseguire synchrone.

risultato è simile:

qual è il modo rigth per scrivere qualcosa che può lanciare applicazioni e sottoattività come 18 filo parralle con async/attendere?

+0

http: // stackoverflow.com/a/11565317/2613020 –

+0

Non è in esecuzione in modo sincrono, l'attività 4 viene avviata prima dell'attività 3, ma termina dopo l'attività 3. –

+0

Prima di tutto dovrebbe scrivere in console prima di tutto poiché attendo attività secondaria più avanti nella funzione – Zwan

risposta

5

Prova questo esempio di codice. Si noti che si completa in circa 6 secondi, il che dimostra che tutti i compiti vengono eseguiti in modo asincrono:

using System; 
using System.Diagnostics; 
using System.Threading; 
using System.Threading.Tasks; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main() 
     { 
      // ThreadPool throttling may cause the speed with which 
      // the threads are launched to be throttled. 
      // You can avoid that by uncommenting the following line, 
      // but that is considered bad form: 

      // ThreadPool.SetMinThreads(20, 20); 

      var sw = Stopwatch.StartNew(); 
      Console.WriteLine("Waiting for all tasks to complete"); 

      RunWorkers().Wait(); 

      Console.WriteLine("All tasks completed in " + sw.Elapsed); 
     } 

     public static async Task RunWorkers() 
     { 
      await Task.WhenAll(
       JobDispatcher(6000, "task 1"), 
       JobDispatcher(5000, "task 2"), 
       JobDispatcher(4000, "task 3"), 
       JobDispatcher(3000, "task 4"), 
       JobDispatcher(2000, "task 5"), 
       JobDispatcher(1000, "task 6") 
      ); 
     } 

     public static async Task JobDispatcher(int time, string query) 
     { 
      var results = await Task.WhenAll(
       worker(time, query + ": Subtask 1"), 
       worker(time, query + ": Subtask 2"), 
       worker(time, query + ": Subtask 3") 
      ); 

      Console.WriteLine(string.Join("\n", results)); 
     } 

     static async Task<string> worker(int time, string query) 
     { 
      return await Task.Run(() => 
      { 
       Console.WriteLine("Starting worker " + query); 
       Thread.Sleep(time); 
       Console.WriteLine("Completed worker " + query); 
       return query + ": " + time + ", thread id: " + Thread.CurrentThread.ManagedThreadId; 
      }); 
     } 
    } 
} 

Ecco come si usa una serie di compiti, invece, in RunWorkers():

public static async Task RunWorkers() 
{ 
    Task[] tasks = new Task[6]; 

    for (int i = 0; i < 6; ++i) 
     tasks[i] = JobDispatcher(1000 + i*1000, "task " + i); 

    await Task.WhenAll(tasks); 
} 
+0

modo interessante per creare thread posso anche aggiungere l'attività secondaria 3 in task asincrona statica worker (int time, string query) methode? – Zwan

+0

reagisce esattamente come quello che mi aspetto da parallele non so ancora esattamente perché alcune parti del mio codice sembrano "gonfie" quando la tua corsa è fluida. Ti inviolerò in seguito.anche grazie lo proverò nel codice di produzione – Zwan

+0

grazie utilizzando il tempo di valore in primo post il tuo codice è di 6 secondi quando la mia prova di 12 secondi non era parallela al primo ... – Zwan