14

I'm bit confused on how async/await can work as parallel so I made a test code here.
I try to send 6 task I simulated with a list.
Each of this task will execute 3 other subtask:

You can copy/paste for 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";
         }


    }
}

Ideally at launch I should read:

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

Then at this point have all task running 6*3 = 18 thread running simultaneously, but it's not what happen here. Thing seem to execute synchronously.

Result is like:

Screenshot

What is the right way to write something that can launch task and subtask as 18 parallel thread with async/await?

7
  • stackoverflow.com/a/11565317/2613020 Commented Feb 1, 2016 at 9:12
  • It's not running synchronously, Task 4 is launched before Task 3 but finishes after Task 3. Commented Feb 1, 2016 at 9:15
  • first of all it should write in console before all since i await subtask later in the function Commented Feb 1, 2016 at 9:30
  • Have a look at these articles. Commented Feb 1, 2016 at 12:18
  • @Zwan: async/await is about asynchrony (concurrency without threads); Parallel is about parallelism (concurrency by using more threads). These are completely different approaches to concurrency, and very very rarely do you need both. Perhaps if you describe what you're actually trying to do, we can suggest a more reasonable solution? Commented Feb 1, 2016 at 13:09

1 Answer 1

17

Try this sample code. Note that it completes in around 6 seconds, which shows that all the tasks are run asynchronously:

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

Here's how you would use an array of tasks instead, 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);
}
Sign up to request clarification or add additional context in comments.

10 Comments

interesting way to build thread can i also add the 3 sub task in static async Task<string> worker(int time, string query) methode?
it react exactly as what i expect from parallele don't know yet exactly why some part of my code seem "bloking" when your's run smooth.will invesstigate later.anyway thanks will try this in production code
thanks using the value time in first post your code is 6 seconde when mine 12 seconde proof something was not runing parallele at first ...
@Servy I removed the version that had the Task.Run(), but I believe it will still need the Task.Run() in worker(). (It previously had await Task.Delay() in it, but to make it more like the OP's code I've replaced it with Thread.Sleep(), which means that now it needs to be run in a Task.)
I come from the future and I tried the code via WPF (swapped "Console" with "Debug"). I noticed that the "All tasks completed in..." didn't show up. Solution: Instead of RunWorkers().Wait(); use await RunWorkers (); and add 'async' to the Main method.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.