1

What is the idiomatic and fastest way to do the following in C#? Say I have a class that has three values (it is always three values so pre allocating 3 tasks is ok):

public class AggregateValues
{
    public double A { get; set;}
    public double B { get; set;}
    public double C { get; set;}
}

public AggregateValues Compute()
{
     //How do I parallize these?
     AggregateValues av = new AggregateValues();
     av.A =  ComputeA();
     av.B =  ComputeB();
     av.C =  ComputeC();

     //Wait for ComputeA, ComputeB, ComputeC to be done

     return av;
}

public double ComputeA()
{
    // Complicated code
}

public double ComputeB()
{
   // Complicated code
}

public double ComputeC()
{
   // Complicated code
}
Ivan
  • 7,448
  • 14
  • 69
  • 134
  • 1
    If you can use asyncs, the WaitAll/WhenAll methods will be the cleanest way to do this. http://stackoverflow.com/questions/25009437/running-multiple-async-tasks-and-waiting-for-them-all-to-complete – Bradley Moorfield Aug 03 '16 at 03:17

2 Answers2

3

You could use Task.WaitAll method to wait for all tasks to complete. A simple solution to your case is provided below.

public AggregateValues Compute()
{
    //How do I parallize these?
    AggregateValues av = new AggregateValues();

    Task taskA = Task.Factory.StartNew(() => av.A = ComputeA());
    Task taskB = Task.Factory.StartNew(() => av.B = ComputeB());
    Task taskC = Task.Factory.StartNew(() => av.C = ComputeC());

    //Wait for ComputeA, ComputeB, ComputeC to be done
    Task.WaitAll(taskA, taskB, taskC);

    return av;
}

await on Task.WhenAll can also be used to wait for all tasks to be completed.

Community
  • 1
  • 1
KDR
  • 478
  • 6
  • 19
  • Thanks that works. I am wondering how efficient "Task taskA = Task.Factory.StartNew(() => av.A = " I guess I can always statically allocate them. – Ivan Aug 03 '16 at 03:46
2

If ComputeA, ComputeB, and ComputeC aren't asynchronous (and they aren't in your code because they return double instead of Task<double>), then you can use Parallel.Invoke:

public AggregateValues Compute()
{
    AggregateValues av = new AggregateValues();
    Parallel.Invoke(
        () => { av.A = ComputeA(); },
        () => { av.B = ComputeB(); },
        () => { av.C = ComputeC(); });
    return av;
}

In your scenario, Parallel.Invoke is slightly better than Task.WaitAll or Task.WhenAll because Parallel.Invoke can reuse the calling thread for one of the tasks.

Michael Liu
  • 52,147
  • 13
  • 117
  • 150