2016-02-01 14 views
5

Jestem trochę zdezorientowany, w jaki sposób async/czekać może pracować jako równolegle, więc zrobiłem kod testowy tutaj: Próbuję wysłać 6 zadań i symulowane z listą. każde z tych zadań wykona 3 inne podzadanie.Async czekać i równolegle

można kopiuj/wklej do testu

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"; 
     } 


    } 
} 

Idealnie przy uruchomieniu powinno czytam:

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

wtedy w tym momencie mieć wszystko zadanie runiczny 6 * 3 = 18 gwint runing jednocześnie ale nie to, co się tutaj dzieje, wydaje się wykonywać synchronizację.

wynik jest jak:

co jest rigth sposób napisać coś, co można uruchomić zadania i podzadania jako 18 parralle nici z async/czekają?

+0

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

+0

To nie działa synchronicznie, zadanie 4 jest uruchamiane przed zadaniem 3, ale kończy się po zadaniu 3. –

+0

Przede wszystkim powinno pisać w konsoli przed wszystkim, ponieważ oczekuję podzadania później w funkcji – Zwan

Odpowiedz

5

Spróbuj tego przykładowego kodu. Zauważ, że to kończy się w około 6 sekund, co pokazuje, że wszystkie zadania są uruchamiane asynchronicznie:

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; 
      }); 
     } 
    } 
} 

Oto jak można wykorzystać szereg zadań zamiast w 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

ciekawy sposób budowania wątku Czy mogę również dodać 3 pod zadania w asynchronicznej statycznej zadaniu metoda pracy (int, zapytanie łańcuchowe)? – Zwan

+0

reaguje dokładnie tak, jak oczekuję od parallele, nie wiem dokładnie, dlaczego część mojego kodu wydaje się "bloking", gdy twój bieg jest płynny. Będziemy śledzić później. W każdym razie, dzięki, spróbujecie tego w kodzie produkcyjnym – Zwan

+0

dzięki temu wykorzystując czas wartości w pierwszy post twój kod jest 6 sekund, gdy mój 12 drugi dowód, że coś nie było początkowo paralele ... – Zwan