2011-07-14 17 views
10

Estoy intentando escribir una consulta LINQ que permita la cancelación mediante el mecanismo CancellationToken que se proporciona en .NET Framework. Sin embargo, no está claro cuál sería la forma correcta de combinar la cancelación y LINQ.Forma correcta de utilizar LINQ con CancellationToken

Con PLINQ, es posible escribir:

var resultSequence = sourceSequence.AsParallel() 
            .WithCancellation(cancellationToken) 
            .Select(myExpensiveProjectionFunction) 
            .ToList(); 

Desafortunadamente, WithCancellation() sólo se aplica a un ParallelEnumerable - por lo que no se puede utilizar con una consulta LINQ a secas. Es posible, por supuesto, utilizar WithDegreeOfParallelism(1) para convertir una consulta en paralelo en una secuencia uno - pero esto es claramente un truco:

var resultSequence = sourceSequence.AsParallel() 
            .WithDegreeOfParallelism(1) 
            .WithCancellation(cancellationToken) 
            .Select(myExpensiveProjectionFunction) 
            .ToList(); 

También me gustaría evitar la creación de una separada Task para esta operación, ya que necesito para hacer esto en varios lugares, y necesito poder controlar en qué subproceso se ejecuta este código en algunos casos.

Entonces, sin escribir mi propia implementación de WithCancellation() - ¿hay alguna alternativa que logre lo mismo?

+1

Sé que esta pregunta era desde hace mucho tiempo, pero lo que estaba mal con sólo el uso de 'AsParallel(). WithCancellation (CancellationToken)' y simplemente dejar que sea PLINQ? –

Respuesta

27

¿Qué tal este enfoque?

var resultSequence = sourceSequence.WithCancellation(cancellationToken) 
         .Select(myExpensiveProjectionFunction) 
         .ToList(); 

static class CancelExtention 
{ 
    public static IEnumerable<T> WithCancellation<T>(this IEnumerable<T> en, CancellationToken token) 
    { 
     foreach (var item in en) 
     { 
      token.ThrowIfCancellationRequested(); 
      yield return item; 
     } 
    } 
} 
+2

Esto realmente es digno de ser una solicitud de función en Connect. –

+0

No soy lo suficientemente bueno para entender si hay algún impacto, o si esto funciona o podría funcionar con AsParallel(), pero me encanta la simplicidad de esta solución, así que estoy votando. –

+8

Si lo cambio a 'return es.TakeWhile (p_item =>! Token.IsCancellationRequested);' ¿tendrá algún impacto en el rendimiento? – itsho

Cuestiones relacionadas