Reputation: 2449
I am trying to make part of my system run in parallel, but some some reason do it wait for each element before it starts the next even though i have not told it to await. I would like to start executing ExecuteItem
for each this.Items
and then continue when they are all done.
bool singleThread = false;
public async Task Execute()
{
if (!this.singleThread)
{
var tasks = this.Items.Select(x => this.ExecuteItem(x)).ToArray();
Task.WaitAll(tasks);
}
else
{
foreach (var item in this.Items)
{
await this.ExecuteItem(item);
}
}
}
private async Task ExecuteItem(IMyItem item)
{
MappedDiagnosticsContext.Set("itemRef", item.ItemRef);
try
{
await this.HandelItem(item);
}
catch (Exception exp)
{
Logger.ErrorException(string.Format("Execution for {0} failed.", item.ItemName), exp);
Logger.Error("Error Message: ", exp.Message);
}
MappedDiagnosticsContext.Remove("itemRef");
}
To make clear my problem my code behaves as if had wrote the following
var tasks = this.Items.Select(x => await this.ExecuteItem(x)).ToArray();
To make sure it was not some kind of linq problem have i rewriten the problem code to the following, however the code still blocks tasks[i] = this.ExecuteItem(this.Items[i]);
Task[] tasks = new Task[this.Items.Count];
for (int i = 0; i < this.Items.Count; i++)
{
Console.WriteLine("Adding " + this.Items[i].ItemName);
tasks[i] = this.ExecuteItem(this.Items[i]);
}
Console.WriteLine("Waiting!!!");
Task.WaitAll(tasks);
Upvotes: 1
Views: 88
Reputation: 31394
Something in HandelItem
is blocking.
async
methods don't run completely asynchronously, they execute synchronously up until the point they hit an await
. So all of ExecuteItem
, up to HandelItem
will run before the tasks
list is built. This synchronous behavior would continue into HandelItem
if it is an async
method, so likely HandelItem
is executing while building up the tasks list.
This is easily seen with this example program:
static void Main(string[] args)
{
var items = Enumerable.Range(1, 2);
Console.WriteLine("Start");
var tasks = items.Select(i => AsyncMethod(i)).ToArray();
Console.WriteLine("Got tasks");
Task.WaitAll(tasks);
Console.WriteLine("Done!");
}
static async Task AsyncMethod(int i)
{
Console.WriteLine("Enter {0}", i);
await AsyncMethod2(i);
await Task.Delay(1000);
Console.WriteLine("Exit {0}", i);
}
static async Task AsyncMethod2(int i)
{
Console.WriteLine("Enter2 {0}", i);
await Task.Delay(2000);
Console.WriteLine("Exit2 {0}", i);
}
It's output is:
Start
Enter 1
Enter2 1
Enter 2
Enter2 2
Got tasks
Exit2 2
Exit2 1
Exit 1
Exit 2
Done!
So both async
methods run while building the task list, up until the point that they have to wait. So if HandelItem
does something non-asynchronous, it will cause blocking.
Upvotes: 3
Reputation: 8180
If you want the tasks to execute in parallel; and wait until all are complete:
await Task.WhenAll(this.Items.Select(item=>this.ExecuteItem(item)));
Upvotes: 2