How to determine when all task is completed

2020-06-12 05:47发布

问题:

here is sample code for starting multiple task

Task.Factory.StartNew(() =>
        {
            //foreach (KeyValuePair<string, string> entry in dicList)

            Parallel.ForEach(dicList,
                entry =>
                {

                    //create and add the Progress in UI thread
                    var ucProgress = (Progress)fpPanel.Invoke(createProgress, entry);

                    //execute ucProgress.Process(); in non-UI thread in parallel. 
                    //the .Process(); must update UI by using *Invoke
                    ucProgress.Process();

                    System.Threading.Thread.SpinWait(5000000);
                });
        });
.ContinueWith(task => 
  {
      //to handle exceptions use task.Exception member

      var progressBar = (ProgressBar)task.AsyncState;
      if (!task.IsCancelled)
      {
          //hide progress bar here and reset pb.Value = 0
      }
  }, 
  TaskScheduler.FromCurrentSynchronizationContext() //update UI from UI thread
  );

when we start multiple task using Task.Factory.StartNew() then we can use .ContinueWith() block to determine when each task finish. i mean ContinueWith block fire once for each task completion. so i just want to know is there any mechanism in TPL library. if i start 10 task using Task.Factory.StartNew() so how do i notify after when 10 task will be finish. please give some insight with sample code.

回答1:

if i start 10 task using Task.Factory.StartNew() so how do i notify after when 10 task will be finish

Three options:

  • The blocking Task.WaitAll call, which only returns when all the given tasks have completed
  • The async Task.WhenAll call, which returns a task which completes when all the given tasks have completed. (Introduced in .NET 4.5.)
  • TaskFactory.ContinueWhenAll, which adds a continuation task which will run when all the given tasks have completed.


回答2:

if i start 10 task using Task.Factory.StartNew() so how do i notify after when 10 task will be finish

You can use Task.WaitAll. This call will block current thread until all tasks are finished.

Side note: you seem to be using Task, Parallel and Thread.SpinWait, which makes your code complex. I would spend a bit of time analysing if that complexity is really necessary.



回答3:

You can use the WaitAll(). Example :

Func<bool> DummyMethod = () =>{
    // When ready, send back complete!
    return true;
};

// Create list of tasks
System.Threading.Tasks.Task<bool>[] tasks = new System.Threading.Tasks.Task<bool>[2];

// First task
var firstTask = System.Threading.Tasks.Task.Factory.StartNew(() => DummyMethod(), TaskCreationOptions.LongRunning);
tasks[0] = firstTask;

// Second task
var secondTask = System.Threading.Tasks.Task.Factory.StartNew(() => DummyMethod(), TaskCreationOptions.LongRunning);
tasks[1] = secondTask;

// Launch all
System.Threading.Tasks.Task.WaitAll(tasks);


回答4:

Another solution:

After the completion of all the operation inside Parallel.For(...) it return an onject of ParallelLoopResult, Documentation:

For returns a System.Threading.Tasks.ParallelLoopResult object when all threads have completed. This return value is useful when you are stopping or breaking loop iteration manually, because the ParallelLoopResult stores information such as the last iteration that ran to completion. If one or more exceptions occur on one of the threads, a System.AggregateException will be thrown.

The ParallelLoopResult class has a IsCompleted property that is set to false when a Stop() of Break() method has been executed.

Example:

ParallelLoopResult result = Parallel.For(...);

if (result.IsCompleted)
{
    //Start another task
}

Note that it advised to use it only when breaking or stoping the loop manually (otherwise just use WaitAll, WhenAll etc).