Simplest Way to Run Three Methods in Parallel in C#

Simplest way to run three methods in parallel in C#

See the TPL documentation. They list this sample:

Parallel.Invoke(() => DoSomeWork(), () => DoSomeOtherWork());

So in your case this should just work:

Parallel.Invoke(
() => results.LeftFront.CalcAi(),
() => results.RightFront.CalcAi(),
() => results.RearSuspension.CalcAi(geom,
vehDef.Geometry.LTa.TaStiffness,
vehDef.Geometry.RTa.TaStiffness));

EDIT: The call returns after all actions have finished executing. Invoke() is does not guarantee that they will indeed run in parallel, nor does it guarantee the order in which the actions execute.

Execute few methods in parallel

Depending on what kind of processing your methods need to do and if they update GUI elements, you can use the following classes:

  • ThreadPool
  • BackgroundWorker
  • Thread

The answers in this question will help you figure out which is the ideal for your scenario.

Evaluating methods in parallel

I guess the least invasive way is using Parallel.Invoke:

long x, y, z, b;
Parallel.Invoke(
() => x = LongCalculation(123),
() => y = LongCalculation2(345),
() => z = LongCalculation3(678),
() => b = LongCalculation4(910)
);

Call methods parallel and combine results

You can run them as 2 Task<T>s. The Result property takes care of the waiting. Approximately:

// untested 
Task<List<Employee>> t1 = Task.Factory.StartNew(() => Method1());
Task<List<Employee>> t2 = Task.Factory.StartNew(() => Method2());

var result = t1.Result.Concat(t2.Result);

How can I run both of these methods 'at the same time' in .NET 4.5?

Here is what you may want to do:

public async Task<PewPew> SomeMethod(Foo foo)
{
// get the stuff on another thread
var cTask = Task.Run(() => GetAllTheCats(foo));
var fTask = Task.Run(() => GetAllTheFood(foo));

var cats = await cTask;
var food = await fTask;

return new PewPew
{
Cats = cats,
Food = food
};
}

public IList<Cat> GetAllTheCats(Foo foo)
{
// Do stuff, like hit the Db, spin around, dance, jump, etc...
// It all takes some time.
return cats;
}

public IList<Food> GetAllTheFood(Foo foo)
{
// Do more stuff, like hit the Db, nom nom noms...
// It all takes some time.
return food;
}

There are two things you need to understand here:

  1. What is diff between this:

    var cats = await cTask;
    var food = await fTask;

And this:

Task.WaitAll(new [] {cTask, fTask});

Both will give you similar result in the sense let the 2 async tasks finish and then return new PewPew - however, difference is that Task.WaitAll() will block the current thread (if that is UI thread, then UI will freeze). instead, await will break down the SomeMethod say in a state machine, and return from the SomeMethod to its caller as it encounters await keyword. It will not block the thread. The Code below await will be scheduled to run when async task is over.


  1. You could also do this:

    var cats = await Task.Run(() => GetAllTheCats(foo));
    var food = await Task.Run(() => GetAllTheFood(foo));

However, this will not start the async tasks simultaneously. Second task will start after the first is over. This is because how the await keyword works.

EDIT: How to use SomeMethod - somewhere at the start of the call tree, you have to use Wait() or Result property - OR - you have to await from async void.
Generally, async void would be an event handler:

public async void OnSomeEvent(object sender, EventArgs ez) 
{
Foo f = GetFoo();
PewPew p = await SomeMethod(f);
}

If not then use Result property.

public Foo2 NonAsyncNonVoidMethod() 
{
Foo f = GetFoo();
PewPew p = SomeMethod(f).Result; //But be aware that Result will block thread

return GetFoo2(p);
}

Run 3 Tasks at a time all the time

Only 3 Max at any given time.

The normal way of doing asynchronous concurrency (terminology note: not parallelism) is to use SemaphoreSlim:

var throttler = new SemaphoreSlim(3);
var task1 = Throttled(m1.FetchAsync);
var task2 = Throttled(m2.FetchAsync);
var task3 = Throttled(m3.FetchAsync);
var task4 = Throttled(m4.FetchAsync);
var task5 = Throttled(m5.FetchAsync);
var task6 = Throttled(m6.FetchAsync);
await Task.WhenAll(tasks);

async Task<T> Throttled<T>(Func<Task<T>> operation)
{
await throttler.WaitAsync();
try { return await operation(); }
finally { throttler.Release(); }
}

Running async methods in parallel

Is there a better to run async methods in parallel, or are tasks a good approach?

Yes, the "best" approach is to utilize the Task.WhenAll method. However, your second approach should have ran in parallel. I have created a .NET Fiddle, this should help shed some light. Your second approach should actually be running in parallel. My fiddle proves this!

Consider the following:

public Task<Thing[]> GetThingsAsync()
{
var first = GetExpensiveThingAsync();
var second = GetExpensiveThingAsync();

return Task.WhenAll(first, second);
}

Note

It is preferred to use the "Async" suffix, instead of GetThings and GetExpensiveThing - we should have GetThingsAsync and GetExpensiveThingAsync respectively - source.

Add and remove Parallel.Invoke actions during runtime

You should use Microsoft's Reactive Framework (aka Rx) - NuGet System.Reactive and add using System.Reactive.Linq; - then all of your ugly code becomes this:

IObservable<MobileEquipment> query =
from detectedDevicesList in Observable.FromAsync(() => GetConnectedDevices.getAsync())
from detectedDevice in detectedDevicesList.ToObservable()
from mobileEquipment in Observable.FromAsync(() => new MakePhoneCall().call(detectedDevice, listBoxLog))
select mobileEquipment;

The full method now correctly returns Task<String>, rather than Task<Task<String>>.

Here it is:

public async Task<String> callWithEveryConnectedDevice(ListBox listBoxLog, Boolean sendAlarms)
{
String TEST_CALLS_COMPLETED = "All test calls completed.";
String TEST_CALLS_FAILED = "One or more test cals failed";

IObservable<MobileEquipment> query =
from detectedDevicesList in Observable.FromAsync(() => GetConnectedDevices.getAsync())
from detectedDevice in detectedDevicesList.ToObservable()
from mobileEquipment in Observable.FromAsync(() => new MakePhoneCall().call(detectedDevice, listBoxLog))
select mobileEquipment;

IList<MobileEquipment> results = await query.ToList();

if (results.Count == 0)
{
UpdateGui.listboxAddItem(listBoxLog, "No devices are connected.", true);
return TEST_CALLS_FAILED;
}

foreach (MobileEquipment mobileEquipment in results)
{
UpdateGui.listboxAddItem(listBoxLog, "Test call result for " + mobileEquipment.serial + " " + mobileEquipment.operador + ": " + mobileEquipment.callSuccess, true);

if (!mobileEquipment.callSuccess && sendAlarms)
{
await SendEmail.sendAlarmEmailsAsync(libreta, asunto, mensaje);
}
}

UpdateGui.listboxAddItem(listBoxLog, TEST_CALLS_COMPLETED, true);

return TEST_CALLS_COMPLETED;
}

How to call same method n times using tasks to run in parallel in c#?

Parallel.For already gives you the necessary marshalling for this sort of task.

    const int n = 5; // No more than "n threads"
Parallel.For(0, SomeNumberList.Count, new ParallelOptions{MaxDegreeOfParallelism = n}, i =>
{
DoSomeWork(i);
}

There is another overload which gives you ParallelLoopState if you need to handle exceptions or break calls based on what is happening in concurrent executions.



Related Topics



Leave a reply



Submit