使用LINQ和CancellationToken的正确方法

LBu*_*kin 10 .net c# linq parallel-processing cancellation

我正在尝试编写一个LINQ查询,该查询将支持使用CancellationToken.NET框架中提供的机制进行取消.但是,目前还不清楚将取消和LINQ结合起来的正确方法是什么.

使用PLINQ,可以编写:

 var resultSequence = sourceSequence.AsParallel()
                                    .WithCancellation(cancellationToken)
                                    .Select(myExpensiveProjectionFunction)
                                    .ToList();
Run Code Online (Sandbox Code Playgroud)

不幸的是,WithCancellation()仅适用于ParallelEnumerable- 因此它不能与普通的旧LINQ查询一起使用.当然,可以使用WithDegreeOfParallelism(1)将并行查询转换为顺序查询 - 但这显然是一个黑客攻击:

 var resultSequence = sourceSequence.AsParallel()
                                    .WithDegreeOfParallelism(1)
                                    .WithCancellation(cancellationToken)
                                    .Select(myExpensiveProjectionFunction)
                                    .ToList();
Run Code Online (Sandbox Code Playgroud)

我还想避免Task为这个操作创建一个单独的,因为我需要在几个地方执行此操作,并且我需要能够控制在某些情况下运行此代码的线程.

因此,如果没有编写我自己的实现WithCancellation()- 是否有另一种方法可以实现同样的目的?

Jin*_*ung 33

这种方法怎么样?

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果我将它改为`return en.TakeWhile(p_item =>!token.IsCancellationRequested);`会对性能产生什么影响? (8认同)
  • 这实际上值得成为Connect上的功能请求. (4认同)