Executing tasks in parallel

后端 未结 5 2011
北恋
北恋 2020-11-27 05:39

Ok, so basically I have a bunch of tasks (10) and I want to start them all at the same time and wait for them to complete. When completed I want to execute other tasks. I re

相关标签:
5条回答
  • 2020-11-27 06:15

    You should almost never use the Task constructor directly. In your case that task only fires the actual task that you can't wait for.

    You can simply call DoWork and get back a task, store it in a list and wait for all the tasks to complete. Meaning:

    tasks.Add(DoWork());
    // ...
    await Task.WhenAll(tasks);
    

    However, async methods run synchronously until the first await on an uncompleted task is reached. If you worry about that part taking too long then use Task.Run to offload it to another ThreadPool thread and then store that task in the list:

    tasks.Add(Task.Run(() => DoWork()));
    // ...
    await Task.WhenAll(tasks);
    
    0 讨论(0)
  • 2020-11-27 06:33

    If you want to run those task's parallel in different threads using TPL you may need something like this:

    public async Task RunTasks()
    {
        var tasks = new List<Func<Task>>
        {
           DoWork,
           //...
        };
    
        await Task.WhenAll(tasks.AsParallel().Select(async task => await task()));
    
        //Run the other tasks
    }
    

    These approach parallelizing only small amount of code: the queueing of the method to the thread pool and the return of an uncompleted Task. Also for such small amount of task parallelizing can take more time than just running asynchronously. This could make sense only if your tasks do some longer (synchronous) work before their first await.

    For most cases better way will be:

    public async Task RunTasks()
    {
        await Task.WhenAll(new [] 
        {
            DoWork(),
            //...
        });
        //Run the other tasks
    }
    

    To my opinion in your code:

    1. You should not wrap your code in Task before passing to Parallel.ForEach.

    2. You can just await Task.WhenAll instead of using ContinueWith.

    0 讨论(0)
  • 2020-11-27 06:33

    The DoWork method is an asynchronous I/O method. It means that you don't need multiple threads to execute several of them, as most of the time the method will asynchronously wait for the I/O to complete. One thread is enough to do that.

    public async Task RunTasks()
    {
        var tasks = new List<Task>
        {
            DoWork(),
            //and so on with the other 9 similar tasks
        };
    
        await Task.WhenAll(tasks);
    
        //Run the other tasks            
    }
    

    You should almost never use the Task constructor to create a new task. To create an asynchronous I/O task, simply call the async method. To create a task that will be executed on a thread pool thread, use Task.Run. You can read this article for a detailed explanation of Task.Run and other options of creating tasks.

    0 讨论(0)
  • 2020-11-27 06:35

    Essentially you're mixing two incompatible async paradigms; i.e. Parallel.ForEach() and async-await.

    For what you want, do one or the other. E.g. you can just use Parallel.For[Each]() and drop the async-await altogether. Parallel.For[Each]() will only return when all the parallel tasks are complete, and you can then move onto the other tasks.

    The code has some other issues too:

    • you mark the method async but don't await in it (the await you do have is in the delegate, not the method);

    • you almost certainly want .ConfigureAwait(false) on your awaits, especially if you aren't trying to use the results immediately in a UI thread.

    0 讨论(0)
  • 2020-11-27 06:36

    Just also add a try-catch block around the Task.WhenAll

    NB: An instance of System.AggregateException is thrown that acts as a wrapper around one or more exceptions that have occurred. This is important for methods that coordinate multiple tasks like Task.WaitAll() and Task.WaitAny() so the AggregateException is able to wrap all the exceptions within the running tasks that have occurred.

    try
    { 
        Task.WaitAll(tasks.ToArray());  
    }
    catch(AggregateException ex)
    { 
        foreach (Exception inner in ex.InnerExceptions)
        {
        Console.WriteLine(String.Format("Exception type {0} from {1}", inner.GetType(), inner.Source));
        }
    }
    
    0 讨论(0)
提交回复
热议问题