2010-02-18 11 views
7

Tengo un método de extensión para IEnumerable que luego itera a través de la colección, hace su trabajo y luego devuelve un nuevo IEnumerable.devolviendo nulo con PLINQ

He intentado usar PLINQ usando .AsParallel(). ForAll() que acelera significativamente las iteraciones (que por supuesto debería hacer), sin embargo, cuando se devuelve la colección, a menudo hay unos pocos objetos en esa colección que son nulos.

Supongo que esto puede deberse a que devuelve la colección antes de que todos los 'negocios' tengan la oportunidad de completarse? si depuro y pongo un punto de interrupción, no hay nulos.

¿Hay algún tipo de método de "espera que esta operación se complete" que debería estar usando?

EDIT: para ser un poco más claro, hay una lógica de negocios en general, la modificación de propiedades, etc. es necesario tener una acción en bucle, en lugar de simplemente seleccionar algo.

+0

¿Nos puede mostrar un ejemplo de código? –

+0

ParallelEnumerable .ForAll() no devuelve nada (void ForAll (...)), no es un IEnumerable - si usa ForAll, no devuelve un enumerable ... Deberá mostrar código. –

+0

disculpe la ambigüedad. el método devuelve la colección, no el forraje. – benpage

Respuesta

1

La respuesta depende de lo que quiere decir con que devuelve, porque el método ForAll no devuelve nada. Invoca al delegado que especifiques en paralelo para todos los elementos de la colección. Me gustaría pensar que su código es el siguiente:

data.AsParallel().ForAll(() => /* calculate and store result somewhere */); 
// more code 

El método ForAll no espera a que todos los delegados para completar, por lo more code puede ejecutar antes de que todos los delegados completa (y también hay que tener cuidado en la store result somewhere ! bits, ya que puede ejecutar simultáneamente para varios delegados)

creo que el código podría ser reescrita más elegante usando el método de Select:

var res = data.AsParallel().Select(() => /* calculate the result */); 

En este cas e, el delegado simplemente devuelve el resultado. El método Where recopila todos los resultados y cuando itera sobre el IEnumerable devuelto, garantiza que todos los delegados terminaron de calcular.

+0

gracias tom - disculpe la ambigüedad, el método devuelve la colección, no se puede devolver desde el principio, hay demasiada lógica de negocios allí. – benpage

+0

En ese caso, debe tener mucho cuidado, ya que las acciones se están ejecutando al mismo tiempo; es casi seguro que necesite algunos bloqueos. PLINQ se usa mejor cuando tiene un código que "devuelve un resultado" (también conocido como "funcional") en lugar de "modifica un estado" (es decir, es imprescindible). –

0

ForAll() no realiza una fusión y regresa inmediatamente. Parallel.ForEach() es probablemente la funcionalidad que está buscando.

es decir, en lugar de:

collection.AsParallel().ForAll(t=>t.doWork());

algo así como

Parallel.ForEach(collection.AsParallel(), t=>t.doWork());

+0

hmmm .. no es bueno - Parallel.ForEach (colección, t => t.doWOrk()); causa el mismo problema, y ​​Parallel.ForEach (collection.AsParallel(), t => t.doWork()); arroja una excepción agregada – benpage

+0

Impar ... 'Parallel.ForEach()' devuelve un 'ParallelLoopResult' que tiene una propiedad' IsCompleted' que puede verificar. Sin embargo, examinaría el contenido de 'AggregateException', quizás algo no esté sucediendo correctamente en la función' doWork() '. – Tanzelax

Cuestiones relacionadas