【问题标题】:Proper way to use LINQ with CancellationToken将 LINQ 与 CancellationToken 一起使用的正确方法
【发布时间】:2011-10-05 17:18:42
【问题描述】:

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

使用 PLINQ,可以编写:

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

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

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

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

那么,除了编写我自己的 WithCancellation() 实现之外,还有其他方法可以实现同样的目标吗?

【问题讨论】:

  • 我知道这个问题是很久以前的问题了,但是使用 AsParallel().WithCancellation(cancellationToken) 并让它成为 PLINQ 有什么问题?

标签: c# .net linq parallel-processing cancellation


【解决方案1】:

这种方法怎么样?

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;
        }
    }
}

【讨论】:

  • 这实际上值得成为 Connect 上的功能请求。
  • 我还不足以了解是否有任何影响,或者这是否有效或可以与 AsParallel() 一起使用,但我喜欢这个解决方案的简单性,所以我赞成。
  • 如果我将其更改为return en.TakeWhile(p_item =&gt; !token.IsCancellationRequested); 会对性能产生影响吗?
猜你喜欢
  • 1970-01-01
  • 2014-08-30
  • 2015-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多