11

I am trying to write a LINQ query that would support cancellation using the CancellationToken mechanism that is provided in the .NET framework. However, it's unclear what the proper way to combine cancellation and LINQ would be.

With PLINQ, it's possible to write:

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

Unfortunately, WithCancellation() only applies to a ParallelEnumerable - so it can't be used with a plain old LINQ query. It's possible, of course, to use WithDegreeOfParallelism(1) to turn a parallel query into a sequential one - but this is clearly a hack:

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

I would also like to avoid creating a separate Task for this operation, as I need to do this in several places, and I need to be able to control which thread this code runs on in some instances.

So, short of writing my own implementation of WithCancellation() - is there an alternative that would achieve the same thing?

LBushkin
  • 129,300
  • 32
  • 216
  • 265
  • 1
    I know this question was from a long time ago, but what was wrong with just using `AsParallel().WithCancellation(cancellationToken)` and just letting it be PLINQ? – Chris Marisic Nov 04 '15 at 16:50

1 Answers1

36

How about this approach?

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;
        }
    }
}
Jin-Wook Chung
  • 4,196
  • 1
  • 26
  • 45
  • 4
    This is actually worthy of being a feature request on Connect. – Pavel Minaev Jul 15 '11 at 00:14
  • I'm not good enough to understand if there's any impact, or if this works or could work with AsParallel(), but I love the simplicity of this solution so I'm upvoting. – Luis Ferrao Mar 12 '13 at 11:37
  • 12
    If I'll change it to `return en.TakeWhile(p_item => !token.IsCancellationRequested);` will make any impact on performance ? – itsho Oct 02 '13 at 14:40