Эффективная оценка foreach ребенка параллельно - PullRequest
7 голосов
/ 27 июня 2010

У меня есть список объектов, на каждом из которых есть метод bool ShouldRun ().

В настоящее время я перебираю список объектов, проверяю mustRun () для каждого объекта и вызываю Run () для первого, возвращающего true

foreach (child in Children)
{
   if (child.ShouldRun())
   {
      child.Run();
      break;
    }
 }

Я бы хотел сделать это параллельно, потому что оценка shouldRun может занять приличное количество времени, и полезно, чтобы более поздние элементы в коллекции начали свою оценку раньше.

Однако я не могу придумать, как это сделать, чтобы удовлетворить этим условиям:

1 Запустить только один предмет

2 Не запускать более поздний элемент, если предыдущий элемент является истинным или еще не завершил оценку

3 Если все «более ранние» элементы вернули false, а средний элемент вернул true, не ждите, пока более поздний элемент завершит оценку, потому что вы знаете, что он не может ничего переопределить ранее.

Я думал о том, чтобы выполнить параллельный запрос "где" linq, чтобы получить все элементы, которые следует выполнить (), а затем отсортировать, но это нарушит условие # 3

Идеи

Справочная информация:

Система предназначена для обобщенной робототехнической системы искусственного интеллекта.

Некоторые задачи с более высоким приоритетом могут быть вызваны сразу известными переменными датчика, например: Я падаю, исправьте это!

другие задачи могут потребовать значительных вычислительных ресурсов (выполнить распознавание изображения с камеры и приблизиться к видимым целям)

другие задачи могут быть выполнены с помощью базы данных или удаленно (найдите список возможных местоположений объектов в базе данных, а затем перейдите туда, чтобы узнать, сможете ли вы попасть в видимый диапазон одного из них)

Некоторые из самих задач имеют дочерние задачи, что, по сути, приведет к рекурсивному запуску этого процесса в подмножестве задач, и задача внука будет передана по цепочке

Ответы [ 4 ]

3 голосов
/ 27 июня 2010

Я не гений PLINQ, но разве этого простого ответа недостаточно?

var childToRun = Children.AsParallel().AsOrdered()
    .Where(x => x.ShouldRun()).FirstOrDefault();
childToRun.Run();  
0 голосов
/ 27 июня 2010

Вы должны быть в состоянии сделать параллельный выбор с присоединенными индексами, затем отсортировать результат по индексу и выбрать первый, который вернул true. У меня нет 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.

0 голосов
/ 27 июня 2010

Я озадачен тем, почему у вас есть флаг "ShouldRun" на каждом дочернем элементе, вместо того, чтобы ранее помещать каждого дочернего элемента, который вы бы пометили как "ShouldRun", в набор "RunThese".

ТогдаВам нужно только спросить, установлен ли размер набора RunThese на ноль или нет, и если не на ноль, запустите их все.Вы можете просто запустить их, когда обнаружите, что должны их запустить.Если вы считаете, что логика ShouldRun стоит дорого, то раскройте ее, как только у вас появится ребенок, чтобы решить, стоит ли ему запускать ребенка.]

0 голосов
/ 27 июня 2010

Просто концепция того, как я бы попытался это сделать.

Запустите все ShouldRun() параллельно.Поместите результаты в упорядоченный список вместе с элементами и индексами элементов (например, ShouldRun () третьего элемента заканчивается значением false, список будет содержать что-то вроде: 2, false, item).

В другом потоке текущий индекс должен начинаться с 0 и периодически проверять упорядоченный список.Если следующий индекс в списке равен текущему, обработайте результат и увеличьте текущий индекс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...