Похоже, проблема заключается в том, как рассчитать маршруты из всех рейсов, соединяющих набор местоположений (места происхождения и назначения?), И рассчитать длину (стоимость?) Каждого маршрута. Кажется, что дорогая работа - это вызов _routeService.Route
и ToTripLength
.
Вычисление 10K комбинаций из 100 локаций тривиально и не требует распараллеливания. Простой запрос LINQ будет работать:
var combinations=( from start in locations
from finish in locations
where start!=finish
select (start,finish))
.ToArray();
Что произойдет после этого, зависит от того, что делает _routeService.Route
. Если это локальная библиотека, то это проблема параллелизма данных, которая пытается вычислить 10K точек данных наиболее эффективным способом. Это может быть обработано с помощью PLINQ
Если это вызов внешней службы, это проблема параллелизма , которая не должна тратить процессорное время на ожидание ответа 10K удаленных запросов.
Предполагая, что _routeService.Route
- это локальная библиотека, можно использовать PLINQ. Однако пара вспомогательных методов облегчит написание запроса:
RouteParameters locationsToParams((Location start,Location finish) combination)
{
return new RouteParameters {
Coordinates = new[]
{
new Coordinate( start.Latitude, start.Longitude ),
new Coordinate( finish.Latitude, finish.Longitude )
}
};
}
RouteResult callRoute(RouteParameters routeParams)
{
_routeService.Route(routeParams, out var routeResults);
return routeResults;
}
var tripLengths = from cmb in combinations.AsParallel()
let routeParams=locationsToParams(cmb)
let result=callRoute(routeParams)
select ToTripLength(result);
var finalResults = tripLengths.ToArray();
AsParallel () будет принимать входной IEnumerable, в этом случае комбинации разбивают его на столько разделов, сколько имеется ядер, а затем используют одну рабочую задачу на раздел. Данные каждого раздела передаются его рабочей задаче, что сводит к минимуму затраты на синхронизацию.
Это может быть использовано как быстрый и довольно грязный способ сделать удаленные запросы 10K, так как каждый вызов Route
будет выполняться для одной из рабочих задач. Это расточительно, потому что блокирует задачу только для ожидания ответа. WithDegreeOfParallelism можно использовать для использования большего количества рабочих задач, чем для ядер, но это по-прежнему тратит время ЦП в ожидании ответа. Блокирующие вызовы начинаются с SpinWait до приостановки потока, что означает, что блокирующий вызов удаленной службы может использовать ядро ЦП, ничего не делая. Это может серьезно нанести ущерб масштабируемости в серверной среде.
var tripLengths = from cmb in combinations.AsParallel()
.WithDegreeOfParalellism(10)
let routeParams=locationsToParams(cmb)
let result=callRoute(routeParams)
select ToTripLength(result);
var finalResults = tripLengths.ToArray();