У меня есть список объектов, каждого с bool ShouldRun () метод на них.
Я в настоящее время выполняю итерации по списку объектов, и проверяю ShouldRun () на каждом объекте и называю Выполнение () на первом для возвращения true
foreach (child in Children)
{
if (child.ShouldRun())
{
child.Run();
break;
}
}
Я хотел бы сделать это параллельно, потому что оценка shouldRun может занять достойное количество времени, и выгодно позволить более поздним элементам в наборе запустить свою оценку рано.
Однако я не могу думать о способе сделать это, которое удовлетворит эти условия:
1 Только выполняет один объект
2 не выполняют более поздний объект, если более ранний объект верен, или не закончил оценивать уже
3, Если все "более ранние" объекты возвратили false, и средний объект возвращает true, не ожидайте на более позднем объекте, чтобы закончить оценивать, потому что Вы знаете, что он ничего не может переопределить ранее.
Я думал о выполнении параллели, "где" linq запрашивают для получения всех объектов, что shouldRun () и затем сортировка, но это нарушит условие № 3
Идеи?
Вводная информация:
Система является для обобщенной робототехники системой AI.
Некоторые более высокие приоритетные задачи могут быть инициированы сразу известными переменными датчика, например: Я падаю, фиксирую его!
другие задачи могли бы быть в вычислительном отношении интенсивными (сделайте распознавание изображений со стороны камеры и приблизьтесь к видимым целям),
другими задачами могла бы быть база данных, или удаленно управляемый (ищите список вероятных объективных местоположений от базы данных и затем перейдите там, чтобы видеть, можно ли войти в дальность видимости одного из них),
Некоторые сами задачи имеют дочерние задачи, который по существу собирается запустить этот процесс рекурсивно в подмножестве задач, и от задачи внука откажутся через цепочку
Я не гений PLINQ, но разве этого более простого ответа недостаточно?
var childToRun = Children.AsParallel().AsOrdered()
.Where(x => x.ShouldRun()).FirstOrDefault();
childToRun.Run();
Просто концепция того, как я бы попытался это сделать.
Выполнять все ShouldRun ()
параллельно. Поместите результаты в упорядоченный список вместе с элементами и индексами элементов (например, ShouldRun () третьего элемента заканчивается на false, список будет содержать что-то вроде: 2, false, item).
В другом потоке сохранить текущий индекс, начинающийся с 0, и периодически проверять упорядоченный список. Если следующий индекс в списке равен текущему, обработайте результат и продвиньте текущий индекс.
Вы должны иметь возможность выполнять параллельный выбор с помощью прикрепленные индексы, затем отсортируйте результат по индексу и выберите первый, который вернул истину
. У меня нет IDE на этой машине, так что это не тестировалось, но что-то вроде:
var runnables = Children.AsParallel()
.Select(child, index =>
new {
Index = index,
ShouldRun = child.ShouldRun(),
Child = child
})
.ToList(); //force evaluation
var firstRunner = runnables.OrderBy(r => r.Index)
.First(r => r.ShouldRun) //assuming at least one
//else use FirstOrDefault and null-check
.Child;
firstRunner.Run();
edit: лучший запрос для первого участника -
var firstRunner = runnables.Where(r => r.ShouldRun) // less stuff to sort later
.OrderBy(r => r.Index)
.First(); // no need for predicate here anymore
edit2: однако это не удовлетворяет вашему условию №3.
Я озадачен тем, почему у вас есть флаг «ShouldRun» на каждом ребенке, вместо того, чтобы ранее поместить каждого ребенка, который вы бы пометили как «ShouldRun», в набор «RunThese».
Тогда вам нужно только спросить, равен ли размер набора RunThese нулю или нет, и если нет, запустите их все.
[Конечно, если вы собираетесь управлять ими, зачем даже отмечать/устанавливать их объединение? Вы можете просто запустить их, когда обнаружите, что должны их запускать. Если вы считаете, что логика ShouldRun стоит дорого, то разветвляйте ее в тот момент, когда у вас есть ребенок, чтобы решить, следует ли вам запускать ребенка.]