While going over some code in a console application, I saw the nested Task.WhenAll in the SecondInitialize function. I decided to test this function with a large Locations List and see how it reacted.
What I saw is that with about 100 locations, 100*100 = 10,000 Calculate calls, the t.Wait() inside of Start takes about 60 seconds to return or sometimes just hang completely. If i try to click Break All the console application doesn't even respond to my click and visual studio crashes.
When using my 'Easier to read version' inside of SecondInitialize, it also takes a while to return. Consistent behavior.
Now the weird part is, whenever I use the debugger and put a breakpoint inside of the SecondInitialize and then hit continue, it will finish in about 5-7 seconds.
So my question is, why is it hanging taking a long time normally when I see it being faster when I debug inside that function? Another question is whether or not the use of Tasks is being utilized correctly
public void Start()
{
var t = CacheInitialize(locations, CancellationToken.None);
t.Wait();
}
public Task CacheInitialize(IList<Location> locations, CancellationToken token)
{
return SecondInitialize(locations, token);
}
public async Task SecondInitialize(IList<Location> locations, CancellationToken token)
{
await Task.WhenAll(locations.Select(first =>
{
return Task.WhenAll(locations.Where(second => !second.Equals(first)).Select(second =>
{
return Calculate(first, second, token);
}));
}));
//Easier to read version of ^
//var tasks = locations.SelectMany(first => locations.Where(second => !second.Equals(first)).Select(second =>
//{
// return Calculate(first, second, token);
//}));
//await Task.WhenAll(tasks);
//No Tasks.
//for (int x = 0; x < locations.Length; x++)
//{
// for (int y = 0; y < locations.Length; y++)
// {
// if (x == y)
// continue;
// await Calculate(locations[x], locations[y], token).ConfigureAwait(false);
// }
//}
}
public async Task<TripLength> Calculate(Location start, Location finish, CancellationToken token)
{
if (start == finish)
return TripLength.Zero;
var parameters = new RouteParameters
{
Coordinates = new []
{
new Coordinate(start.Latitude, start.Longitude),
new Coordinate(finish.Latitude, finish.Longitude)
}
};
var route = await RunRoute(parameters, token);
return ToTripLength(route);
}
protected Task<RouteResult> RunRoute(RouteParameters routeParams, CancellationToken token)
{
return Task.Run(async () =>
{
var routingTask = Task.Run(() =>
{
RouteResult routeResults;
var status = _routeService.Route(routeParams, out routeResults);
return routeResults;
}, token);
return await routingTask.ConfigureAwait(false);
}, token);
}