Simplest way to run three methods in parallel in C# - c#

I have three methods that I call to do some number crunching that are as follows
results.LeftFront.CalcAi();
results.RightFront.CalcAi();
results.RearSuspension.CalcAi(geom, vehDef.Geometry.LTa.TaStiffness, vehDef.Geometry.RTa.TaStiffness);
Each of the functions is independent of each other and can be computed in parallel with no dead locks.
What is the easiest way to compute these in parallel without the containing method finishing until all three are done?

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.

You can do this with tasks too (nicer if you later need Cancellation or something like results)
var task1 = Task.Factory.StartNew(() => results.LeftFront.CalcAi());
var task2 = Task.Factory.StartNew(() => results.RightFront.CalcAi());
var task3 = Task.Factory.StartNew(() =>results.RearSuspension.CalcAi(geom,
vehDef.Geometry.LTa.TaStiffness,
vehDef.Geometry.RTa.TaStiffness));
Task.WaitAll(task1, task2, task3);

In .NET 4, Microsoft introduced the Task Parallel Library which was designed to handle this kind of problem, see Parallel Programming in the .NET Framework.

To run parallel methods which are independent of each other ThreadPool.QueueUserWorkItem can also be used. Here is the sample method-
public static void ExecuteParallel(params Action[] tasks)
{
// Initialize the reset events to keep track of completed threads
ManualResetEvent[] resetEvents = new ManualResetEvent[tasks.Length];
// Launch each method in it's own thread
for (int i = 0; i < tasks.Length; i++)
{
resetEvents[i] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(new WaitCallback((object index) =>
{
int taskIndex = (int)index;
// Execute the method
tasks[taskIndex]();
// Tell the calling thread that we're done
resetEvents[taskIndex].Set();
}), i);
}
// Wait for all threads to execute
WaitHandle.WaitAll(resetEvents);
}
More detail about this function can be found here:
http://newapputil.blogspot.in/2016/03/running-parallel-tasks-using.html

var task1 = SomeLongRunningTask();
var task2 = SomeOtherLongRunningTask();
await Task.WhenAll(task1, task2);
The benefit of this over Task.WaitAll is that this will release the thread and await the completion of the two tasks.

Related

Stuck at Task.WaitAll(tasks.ToArray()) while using Task.Start to trigger the tasks

We had something like below
List<string> uncheckItems = new List<string>();
for (int i = 0; i < 100; i++)
{
uncheckItems.Add($"item {i + 1}");
}
var tasks = uncheckItems.Select(item =>
new Task(async () => await ProcessItem(item))
);
// Do some preparations
foreach (var task in tasks)
{
task.Start();
}
Task.WaitAll(tasks.ToArray());
Console.WriteLine("=====================================================All finished");
It seems to make sense but the program never able to reach the all finished line.
And if I adjust the workflow to run tasks immediately like remove the task.Start() loop and change to
var tasks = uncheckItems.Select(async item =>
await ProcessItem(item)
);
Then it works.
However, I wonder
Why it stucks?
Is there any way we can keep the workflow(create tasks without trigger them directly and start them later on) and still able to utilize WaitAll()?
The reason is the lazy enumeration evaluation, you are starting different tasks than waiting with Task.WaitAll. This can be fixed for example with next:
var tasks = uncheckItems.Select(item =>
new Task(async () => await ProcessItem(item))
)
.ToArray();
Though it will not achieve your goal (as I understand) of waiting all ProcessItem to finish. You can do something like new Task(() => ProcessItem(item).GetAwaiter().GetResult()) but I think it would be better to change your approach, for example make ProcessItem return a "cold" task or using your second snippet and moving tasks creation to the point where they needed to be started.
You should be next to the world expert in Task to be using the constructor. The documentation warns against that:
This constructor should only be used in advanced scenarios where it is required that the creation and starting of the task is separated.
Rather than calling this constructor, the most common way to instantiate a Task object and launch a task is by calling the static Task.Run(Action) or TaskFactory.StartNew(Action) method.
If a task with no action is needed just for the consumer of an API to have something to await, a TaskCompletionSource should be used.
The Task constructor produces a non-started Task that will only start when Task.Start() is invoked, as you discovered.
The Task constructor also receives an Action (or Action<T>), so the return value is ignored. That means that, after started, the task will end as soon as async () => await ProcessItem(item) yields.
What you need is:
await Task.WhenAll(Enumerable.Range(0, 100).Select(i => ProcessItem($"item {i + 1}"));
Or, if you really have to block:
Task
.WhenAll(Enumerable.Range(0, 100).Select(i => ProcessItem($"item {i + 1}"))
.GetAwaiter().GetResult();
Get the select out of there.
List<string> uncheckItems = new List<string>();
for (int i = 0; i < 100; i++)
{
uncheckItems.Add($"item {i + 1}");
}
var tasks = new List<Task>();
foreach(var item in uncheckedItems) {
tasks.Add(Task.Run(() => ProcessItem(item)));
}
Task.WaitAll(tasks.ToArray());
Console.WriteLine("========All finished");
https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.waitall?view=net-6.0

Mixing async tasks with blocking sync task

I am writing a set of async tasks that go away an download and parse data, however I am running in to a bit of a blank with the next step where I am updating a database.
The issue is that for the sake of performance I am using a TableLock to load rather large datasets, so what I am wanting to do is have my import service wait for the first Task to return, start the import. Should another Task complete while the first import is running the process joins a queue and waits for the import service is complete for task 1.
eg.
Async
- Task1
- Task2
- Task3
Sync
- ImportService
RunAsync Tasks
Task3 returns first > ImportService.Import(Task3)
Task1 return, ImportService is still running. Wait()
ImportService.Complete() event
Task2 returns. Wait()
ImportService.Import(Task1)
ImportService.Complete() event
ImportService.Import(Task2)
ImportService.Complete() event
Hope this makes sense!
You can't really use await here, but you can wait on multiple tasks to complete:
var tasks = new List<Task)();
// start the tasks however
tasks.Add(Task.Run(Task1Function);
tasks.Add(Task.Run(Task2Function);
tasks.Add(Task.Run(Task2Function);
while (tasks.Count > 0)
{
var i = Task.WaitAny(tasks.ToArray()); // yes this is ugly but an array is required
var task = tasks[i];
tasks.RemoveAt(i);
ImportService.Import(task); // do you need to pass the task or the task.Result
}
Seems to me however that there should be a better option. You could let the tasks and the import run and add a lock on the ImportService part for instance:
// This is the task code doing whatever
....
// Task finishes and calls ImportService.Import
lock(typeof(ImportService)) // actually the lock should probably be inside the Import method
{
ImportService.Import(....);
}
There are several things bothering me with your requirements (including using a static ImportService, static classes are rarely a good idea), but without further details I can't provide better advice.
While this is likely not the most graceful solution, I would try launching the work tasks and have them place their output in a ConcurrentQueue. You could check the queue for work on a timer until all tasks are completed.
var rand = new Random();
var importedData = new List<string>();
var results = new ConcurrentQueue<string>();
var tasks = new List<Task<string>>
{
new Task<string>(() =>
{
Thread.Sleep(rand.Next(1000, 5000));
Debug.WriteLine("Task 1 Completed");
return "ABC";
}),
new Task<string>(() =>
{
Thread.Sleep(rand.Next(1000, 5000));
Debug.WriteLine("Task 2 Completed");
return "FOO";
}),
new Task<string>(() =>
{
Thread.Sleep(rand.Next(1000, 5000));
Debug.WriteLine("Task 3 Completed");
return "BAR";
})
};
tasks.ForEach(t =>
{
t.ContinueWith(r => results.Enqueue(r.Result));
t.Start();
});
var allTasksCompleted = new AutoResetEvent(false);
new Timer(state =>
{
var timer = (Timer) state;
string item;
if (!results.TryDequeue(out item))
return;
importedData.Add(item);
Debug.WriteLine("Imported " + item);
if (importedData.Count == tasks.Count)
{
timer.Dispose();
Debug.WriteLine("Completed.");
allTasksCompleted.Set();
}
}).Change(1000, 100);
allTasksCompleted.WaitOne();

Async call for delegate in cycle

I need to call asynchronously number of delegates for the same function.
The question is how i should treat the call back function ?
we have couple of delegates running so CallbackMethod doesn't mean that that all async delegates finished.
AsyncMethodCaller c = new AsyncMethodCaller(instance.dummyMethod);
for (int i = 0; i < 100; i++)
{
IAsyncResult res = c.BeginInvoke(5000,
out dummy,
new AsyncCallback(CallbackMethod),
"executed on thread {0}, with result value \"{1}\".");
}
I would consider looking at using Tasks provided with TPL.
var task1 = Task.Run(() => instance.dummyMethod)
.ContinueWith((completedTask) => Console.WriteLine("Each callback here. Result: " + completedTask.Result));
// Blocks calling thread until all tasks are done.
Task.WaitAll(new [] { task1, task2 });
The WaitAll all ensures that all Tasks are done before continuing on the main thread. The above allows you to implement individual callbacks.
Alternatively use a single callback when All the async methods are complete:
Task.Factory.ContinueWhenAll(new [] { task1, task2 },
(allTasks) => Console.WriteLine("Callback when all are done."));
I would be inclined to use Microsoft's Reactive Framework (NuGet "Rx-Main") for this as it would be so much simpler.
Here's the code:
var query =
from n in Observable.Range(0, 100)
from dummy in Observable.Start(() => instance.dummyMethod())
select dummy;
query
.Subscribe(
dummy =>
{
Console.WriteLine(dummy.ToString());
},
() =>
{
Console.WriteLine("Done.");
});
The .Subscribe method has a callback for each dummy value produced as well as a "done" callback when all the values have been returned.
The query runs on multiple threads automatically for you.

Threading: Application Freezes after using Thread.Join()

I understand that the .Join() causes the threads to pause and wait till a thread finishes its work but how can I avoid the UI from getting frozen? This is what my codes look like"
Thread dataThread = new Thread(()=> data = getData(id));
dataThread.Start();
dataThread.Join();
Thread storingThread = new Thread(()=> storeData(data));
storingThread.Start();
I need to have the Join since the first thread returns an object containing data that needs to be stored through the second thread. But this causes a UI freeze. How can I implement these in maybe a Background thread? What do yall think I should change?
If you are using .Net framework >= 4.5 you can use Tasks
await Task.Run(() => data = getData(id));
await Task.Run(() => storeData(data));
Or in one command
await Task.Run(() => storeData(getData(id)));
If you don't have to wait till it's finished you can also do:
Task.Run(() => storeData(getData(id)));
It seems you don't need two threads:
Thread dataThread = new Thread(() => storeData(getData(id)));
dataThread.Start();
Note, that Task is preferable to Thread. Also, you probably should make use of await.
The answer has already been given. Just as an extra, I give mine.
You can also use ContinueWith like this:
Task<string>.Factory.StartNew(() => "Hey!").ContinueWith(t => Console.WriteLine(t.Result));
Put the whole work into one thread so the UI doesn't stop:
ThreadPool.QueueUserWorkItem( () => storeData(getData(id)));
Or for .Net 4
Task.Factory.StartNew(() => storeData(getData(id)));
Use the async / await keywords. Small example code:
private async void Method()
{
var result = await ExecuteAsync();
// result == true
}
private async Task<bool> ExecuteAsync()
{
//run long running action
return true;
}
In .net 4.0 you need to install Microsoft.Bcl.Async to use this feature.
A good introduction in this feature can be read on http://blog.stephencleary.com/2012/02/async-and-await.html

Run two task asynchronously

I'm running a synchronous method. Inside it I have to run two big method, so I was thinking to run them asynchronously.. I was thinking something like
public void MyFunc()
{
var doWorkTask_1 = DoWork1();
var doWorkTask_2 = DoWork2();
var result1 = await doWorkTask_1;
var result2 = await doWorkTask_2;
if(result1 == result2)
....
Thread.Sleep(syncInterval);
}
To do this i need that:
DoWork1 and DoWork2 are asynchronous;
MyFunc is asynchrous too;
But no method is asynchronous!!!
SO I tried to do in another way:
public void MyFunc()
{
var doWorkTask_1 = Task.Run(() => DoWork1());
var doWorkTask_2 = Task.Run(() => DoWork2());
var result1 = doWorkTask_1.Result;
var result2 = doWorkTask_2.Result;
if(result1 == result2)
....
Thread.Sleep(syncInterval);
}
So, 1st question:
Do I have written same thing in two different ways?
2nd question. I have to run the MyFunc method every X time, so I call it in this way:
Task.Factory.StartNew(MyFunc);
Can I call it simply
MyFunc();
My question is because inside myFunc I have a Thread.Sleep. Can I let sleep the main thread or is better to let sleep a thread inside the main?
I hope I have been clear.
Thank you.
Have I written same thing in two different ways?
No. Your first method will execute two units of work in parallel, and will asynchronously wait on the first one, then the second one.
Your second method will execute two units of work in parallel, and will synchronously wait on the first one, then on the second one.
Can I let sleep the main thread or is better to let sleep a thread
inside the main?
That depends on what your application is doing. You could turn MyFunc to be async so you can use Task.Delay instead, which internally uses a timer and doesn't block (and you may also pass it a CancellationToken if needed):
public async Task MyFuncAsync()
{
// Do work
await Task.Delay(syncInterval);
}
Side note:
It seems to me like you may be using async over sync, which in general is a questionable approach. I would advise against it.
Instead, like in your first example, explicitly invoke Task.Run on these workers:
public async Task MyFuncAsync()
{
var firstTask = Task.Run(() => DoWork1());
var secondTask = Task.Run(() => DoWork2());
await Task.WhenAll(new[] { firstTask, secondTask });
await Task.Delay(syncInterval);
}
Use Task.WhenAll to create a new task, encapsulating both your worker tasks.
Creates a task that will complete when all of the supplied tasks have
completed.
https://msdn.microsoft.com/en-us/library/hh194874%28v=vs.110%29.aspx
public async void MyFunc()
{
var doWorkTask_1 = DoWork1();
var doWorkTask_2 = DoWork2();
var results = await Task.WhenAll(doWorkTask_1, doWorkTask_2);
}
If you can't do async all the way, and by asynchronous you mean that you want to process DoWork1 and DoWork2 concurrently on different threads then you can use Task.Run to offload the work to a different thread and Task.WaitAll to wait synchronously for both tasks to complete:
public void MyFunc()
{
var task1 = Task.Run(() => DoWork1());
var task2 = Task.Run(() => DoWork2());
Task.WaitAll(task1, task2);
if (task1.Result == task2.Result)
{
// ...
}
Thread.Sleep(syncInterval);
}
Now, since this uses 3 threads (two ThreadPool threads in Task.Run and the calling thread blocked on Task.WaitAll) when we only need 2 we can simplify and optimize the example by executing one of the operations on the calling thread:
public void MyFunc()
{
var task1 = Task.Run(() => DoWork1());
var result2 = DoWork2();
if (task1.Result == result2)
{
// ...
}
Thread.Sleep(syncInterval);
}

Categories