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);
}