如何取消可观察的序列

时间:2011-07-20 09:36:22

标签: c# system.reactive cancellation

我有一个非常简单的IObservable<int>,它每500毫秒充当一个脉冲发生器:

var pulses = Observable.GenerateWithTime(0, i => true, i => i + 1, i => i,
                                         i => TimeSpan.FromMilliseconds(500))

我有CancellationTokenSource(用于取消同时进行的其他工作)。

如何使用取消令牌源取消我的可观察序列?

5 个答案:

答案 0 :(得分:7)

这是一个旧线程,但仅供将来参考,这是一种更简单的方法。

如果你有CancellationToken,你可能已经在处理任务了。所以,只需将其转换为Task,让框架进行绑定:

using System.Reactive.Threading.Tasks;
...
var task = myObservable.ToTask(cancellationToken);

这将创建一个内部订户,将在取消任务时处理。在大多数情况下,这将起到作用,因为大多数可观察者只在有订阅者时才生成值。

现在,如果你有一个实际的observable需要由于某种原因被处置(如果父任务被取消,可能是一个不再重要的热观察),这可以通过延续来实现:

disposableObservable.ToTask(cancellationToken).ContinueWith(t => {
    if (t.Status == TaskStatus.Canceled)
        disposableObservable.Dispose();
});

答案 1 :(得分:6)

如果您正在使用GenerateWithTime(现在替换为Generate传入时间跨度函数重载),您可以替换第二个参数来评估取消令牌的状态,如下所示:

var pulses = Observable.Generate(0,
    i => !ts.IsCancellationRequested,
    i => i + 1,
    i => i,
    i => TimeSpan.FromMilliseconds(500));

或者,如果您设置取消令牌的事件可以转换为可观察的事件,您可以使用以下内容:

pulses.TakeUntil(CancelRequested);

我在http://www.thinqlinq.com/Post.aspx/Title/Cancelling-a-Reactive-Extensions-Observable也发布了更详细的解释。

答案 2 :(得分:2)

您可以将IObservable订阅与CancellationTokenSource与以下代码段连接

var pulses = Observable.GenerateWithTime(0,
    i => true, i => i + 1, i => i,
    i => TimeSpan.FromMilliseconds(500));

// Get your CancellationTokenSource
CancellationTokenSource ts = ...

// Subscribe
ts.Token.Register(pulses.Subscribe(...).Dispose);

答案 3 :(得分:0)

您从订阅中获得了IDisposable个实例。请致电Dispose()

答案 4 :(得分:0)

这里有两个方便的运算符,用于取消可观察的序列。它们之间的区别在于取消情况下的情况。 TakeUntil导致序列(OnCompleted的正常完成,而WithCancellation导致异常的终止(OnError)。

/// <summary>Returns the elements from the source observable sequence until the
/// CancellationToken is canceled.</summary>
public static IObservable<TSource> TakeUntil<TSource>(
    this IObservable<TSource> source, CancellationToken cancellationToken)
{
    return source
        .TakeUntil(Observable.Create<Unit>(observer =>
            cancellationToken.Register(() => observer.OnNext(default))));
}

/// <summary>Ties a CancellationToken to an observable sequence. In case of
/// cancellation propagates an OperationCanceledException to the observer.</summary>
public static IObservable<TSource> WithCancellation<TSource>(
    this IObservable<TSource> source, CancellationToken cancellationToken)
{
    return source
        .TakeUntil(Observable.Create<Unit>(o => cancellationToken.Register(() =>
            o.OnError(new OperationCanceledException(cancellationToken)))));
}

用法示例:

var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));

var pulses = Observable
    .Generate(0, i => true, i => i + 1, i => i, i => TimeSpan.FromMilliseconds(500))
    .WithCancellation(cts.Token);