2010-06-26 15 views
7

Tengo una lista de objetos, cada uno con un bool ShouldRun() método en ellos.Evaluación del niño Foreach eficiente en paralelo

estoy iterando la actualidad más de la lista de objetos, y la comprobación de ShouldRun() de cada objeto, y llamando Run() en la primera de ellas para volver verdadero

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

me gustaría hacer esto de forma paralela , porque la evaluación de shouldRun puede tomar una buena cantidad de tiempo, y es ventajoso permitir que los elementos posteriores de la colección comiencen su evaluación con anticipación.

Sin embargo, no puedo pensar en una manera de hacer esto que satisfaga estas condiciones:

1 ejecutar sólo un elemento

2 No ejecute un artículo más adelante si un artículo anterior es cierto, o tiene aún no se ha terminado de evaluar

3 Si todos los elementos "anteriores" han resultado falsos y un elemento del medio es verdadero, no espere más para finalizar la evaluación porque sabe que no puede anular nada anteriormente.

se me ocurrió hacer un paralelo "donde" consulta LINQ para recuperar todos los elementos que shouldRun() y después de clasificación, pero esto va a violar la condición # 3

ideas?

información Antecedentes:

El sistema es un sistema de inteligencia artificial robótica generalizada.

Algunas de las tareas de mayor prioridad se pueden desencadenar mediante variables de sensor conocidas de inmediato, por ejemplo: ¡me estoy cayendo, arréglenlo! otros

tareas podrían ser computacionalmente intensivos (hacer el reconocimiento de imágenes de la cámara, y el enfoque de objetivos visibles)

otras tareas podrían ser la base de datos o remotamente accionados (consultar una lista de ubicaciones objetivos probables a partir de una base de datos, y luego navegue hasta allí para ver si puede entrar en el rango visible de uno de ellos)

Algunas de las tareas tienen tareas hijo, lo que esencialmente va a iniciar este proceso de forma recursiva en un subconjunto de tareas, y la tarea de nieta pasar a través de la cadena

+1

Pregunta interesante. Defina "cantidad decente de tiempo", si puede, y tal vez lo que hace que cada cheque sea tan largo. ¿Está haciendo una llamada a la base de datos? ¿Servidor remoto? ¿Tiene su propio bucle interno que está teniendo lugar? Ese tipo de cosas. –

+0

podría ser todo lo anterior. Ver ediciones –

+0

Creo que a su código de ejemplo le falta un operador ('var') –

Respuesta

3

No soy un genio de PLINQ, pero ¿no bastaría con esta simple respuesta?

var childToRun = Children.AsParallel().AsOrdered() 
    .Where(x => x.ShouldRun()).FirstOrDefault(); 
childToRun.Run(); 
+0

Estoy investigando esta solución. si el AsOrdered se encarga de la restricción # 3 ¡usted gana! –

0

Just ac oncept de manera que trataría de hacerlo.

Ejecute todos los ShouldRun() 's en paralelo. Coloque los resultados en la lista ordenada junto con los elementos e índices de los elementos (por ejemplo, ShouldRun() del tercer elemento termina con falso, la lista contendrá algo así como: 2, falso, elemento).

En otro hilo, mantenga el índice actual comenzando con 0 y revise la lista ordenada periódicamente. Si el siguiente índice en la lista es igual a la actual, procese el resultado y avance el índice actual.

0

Debería poder hacer una selección paralela con los índices adjuntos, luego ordenar el resultado según el índice y elegir el primero que devolvió true.No tengo un IDE en esta máquina por lo que este no se ha probado, pero algo como:

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

edición: mejor consulta para el primer corredor -

var firstRunner = runnables.Where(r => r.ShouldRun) // less stuff to sort later 
          .OrderBy(r => r.Index) 
          .First(); // no need for predicate here anymore 

Edit2: esto no satisface su condición # 3, sin embargo.

+0

¿No viola esta solución la tercera condición? –

0

Me sorprende por qué tiene una bandera "ShouldRun" en cada niño, en lugar de haber colocado antes cada niño que marcaría como "ShouldRun" en un conjunto "RunThese".

Luego solo tiene que preguntar si RunThese set size es zero o no, y si no es cero, ejecútelos todos.

[Por supuesto, si va a ejecutarlos, ¿por qué incluso marcarlos/establecerlos? Podrías simplemente iniciarlos cuando descubras que debes ejecutarlos. Si cree que la lógica ShouldRun es costosa, bótela en el momento en que tenga al niño para decidir si debe ejecutar al niño.]

+0

shouldRun responde al estímulo externo. como el mundo está cambiando externo a la IA, la IA necesita poder responder. ShouldRun está evaluando el mundo para ver si se aplican ciertas condiciones. –

+0

No debe estar * sondeando * para eventos externos. Para cada niño, construya una red de discriminación que busque secuencias de eventos externos. A medida que esos eventos ocurren de forma asincrónica (y su robot se da cuenta de ellos), agregue al estado la red de discriminación (piense en estas redes como suscriptores de eventos publicados). Cuando una discriminación finalmente dice "Verdadero", publique lo que está llamando al niño en una lista de ejecución administrada por prioridad, para ser procesada por la siguiente CPU disponible. –

+0

¿Cómo lo haría yo además de las encuestas? El mundo no puede notificarme de los cambios en su estado. La red de discriminación es solo un método diferente de sondeo, ¿verdad? –

Cuestiones relacionadas