Rx and tasks - cancel running task when new task is spawned?

前端 未结 2 1356
醉话见心
醉话见心 2020-12-16 04:20

I have an user interaction scenario I\'d like to handle with Rx.

The scenario is similar to the canonical \"when user stops typing, do some work\" (usually, search

2条回答
  •  别那么骄傲
    2020-12-16 05:02

    Do you have to work with Tasks?

    If you're happy to work purely with Observables then you can do this nicely yourself.

    Try doing something like this:

    var query =
        Observable.Create(o =>
        {
            var cancelling = false;
            var cancel = Disposable.Create(() =>
            {
                cancelling = true;
            });
            var subscription = Observable.Start(() =>
            {
                for (var i = 0; i < 100; i++)
                {
                    Thread.Sleep(10); //1000 ms in total
                    if (cancelling)
                    {
                        Console.WriteLine("Cancelled on {0}", i);
                        return -1;
                    }
                }
                Console.WriteLine("Done");
                return 42;
            }).Subscribe(o);
            return new CompositeDisposable(cancel, subscription);
        });
    

    This observable is doing some hard work in the for loop with the Thread.Sleep(10);, but when the observable is disposed the loop is exited and the intensive CPU work ceases. Then you can use the standard Rx Dispose with the Switch to cancel the in progress work.

    If you'd like that bundled up in a method, then try this:

    public static IObservable Start(Func, T> work)
    {
        return Observable.Create(o =>
        {
            var cancelling = false;
            var cancel = Disposable
                .Create(() => cancelling = true);
            var subscription = Observable
                .Start(() => work(() => cancelling))
                .Subscribe(o);
            return new CompositeDisposable(cancel, subscription);
        });
    }
    

    And then call it with a function like this:

    Func, int> work = cancelling =>
    {
        for (var i = 0; i < 100; i++)
        {
            Thread.Sleep(10); //1000 ms in total
            if (cancelling())
            {
                Console.WriteLine("Cancelled on {0}", i);
                return -1;
            }
        }
        Console.WriteLine("Done");
        return 42;
    };
    

    Here's my code that proved this worked:

    var disposable =
        ObservableEx
            .Start(work)
            .Subscribe(x => Console.WriteLine(x));
    
    Thread.Sleep(500);
    disposable.Dispose();
    

    I got "Cancelled on 50" (sometime "Cancelled on 51") as my output.

提交回复
热议问题