I am new to async and parallel programming and my question revolves around attempting to run a method that takes a couple parameters, and then execute that method in parallel. I need to run this in parallel because the method being called is updating PLC's on my factory floor. If it is down synchrounsly, this process can take nearly 10 minutes because of how many there are. I am able to get the method to run once, using the last PLC in my custom class, but won't run for the other PLC's in my list. Sample code below:
List<Task> task = new List<Task>();
foreach(PLC plc in PlcCollection)
{
string plcName = plc.Name;
string tagFormat = plc.TagFormat
tasks.Add(Task.Run(async () => await MakeTags(plcName, tagFormat)));
}
Parallel.ForEach(tasks, task => task.Start());
// Code to be done after tasks are complete
public async Task MakeTags(string plcName, string tagFormat)
{
//Code to update the PLC's
}
The method makeTags works like it should when called - it updates the PLC correctly. But it only runs once, and only for one of my PLC values. I have also tried Task.WhenAll(tasks) instead of the Parallel.ForEach, with the same problem. Does anyone have any advice and feedback on what I am doing wrong and anything that I could try?
Thanks!
EDIT: To clarify - I am expecting the MakeTags method to be executed in parallel for however many PLC's there are in the PlcCollection (the number will be variable). What I am getting is that the MakeTags method is only being called once, for one PLC element, when there are multiple PLC's in the collection. This process is started from a web app and then the server takes care of the rest. No UI elements are being updated or changed. It's all behind the scenes work.
EDIT 2: See below for a screenshot of the Debugger. In this example 2 PLC's (TTC_WALL and RR_HEPA_EE) are loaded into my list of tasks. However, only the RR_HEPA_EE is processed and then the program completes without an exception being thrown.
Edit 3: I made changes and now code looks like the following:
List<Task> task = new List<Task>();
foreach(PLC plc in PlcCollection)
{
//plcName and tagFormat are just strings
tasks.Add(MakeTags(plcName, tagFormat);
}
Task.WhenAll(tasks).ContinueWith(t =>
{
//Code to do
Console.WriteLine("****PLC Update Complete*****");
});
return; //program ends
public async Task MakeTags(string plcName, string tagFormat)
{
await Task.Run(() =>
{
Console.WriteLine("Updating PLC " + plcName);
//Code to update the PLC's
Console.WriteLine("PLC Updated for :" + plcName);
});
return;
}
However I am still getting only one of the tasks to run. Debugger screenshot below, showing only 1 of the 2 PLC's were updated. I should be seeing a console line saying "PLC Updated for TTC_WALL" as well.


MakeTagsfor all the PLC's at once, or you want to limit the concurrency of the asynchronous operations?Task.Run()? This call queues a worker thread on the threadpool, which is not necessary sinceMakeTags()is asynchronous and is presumably IO-bound. All you need to do is addMakeTags(plcName, tagFormat)to yourTasklist then await the result usingTask.WhenAll(). Additionally, you don't need to useParallel.ForEachto "start" the work. When you invokeTask.Run(), a thread is queued to the threadpool and will be run as allowed by your task scheduler. In the case of invoking async methods, they begin when invoked.tasks.Add(MakeTags(plcName, tagFormat)thenTask.WhenAll(tasks.ToArray());?Taskjust represents an asynchronous operation. It is not shorthand for a thread or parallelism. The distinction is important and one that you should research, but outside the scope of comment discussion. To answer your question, yes, the code you posted should do what you want. It's worth noting that ifMakeTags()contains CPU-intensive code, it could place a significant load on the server. If it's IO-bound, this should not be an issue.MakeTags.