Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Observable.Defer - need some clarification as to what exactly it does

Say I want to generate an asynchronous stream of random numbers that pumps out a new value every 100 milliseconds. While trying to come up with a solution, my first attempt looked something like this:

        var random = new Random();
        Observable.Start(() => random.Next())
                  .Delay(TimeSpan.FromMilliseconds(100))
                  .Repeat()
                  .Subscribe(Console.WriteLine);

If you try and run this, you'll notice that it just keeps repeating the same value over and over again. OK, I guess I misunderstood how Repeat works. After playing around for a bit, I came up with this and it worked:

        var random = new Random();
        Observable.Defer(()=> Observable.Start(() => random.Next()))
                  .Delay(TimeSpan.FromMilliseconds(100))
                  .Repeat()
                  .Subscribe(Console.WriteLine);

So I went to the MSDN documentation to understand what Defer is actually doing, and this is what it says:

Returns an observable sequence that invokes the observable factory whenever a new observer subscribes.

I guess my confusion is this: in my code sample, I'm only ever subscribing to the Observable once, so why is it seemingly invoking the Observable.Start(...) over and over? Or am I misunderstanding Repeat()? Any clarification would be awesome.

like image 213
BFree Avatar asked Jul 12 '12 18:07

BFree


1 Answers

You are misunderstanding Repeat. Basically, Repeat will keep resubscribing to an observable every time it is completed.

Observable.Start apparently caches the value the first time you call Subscribe and is returning it each time you subscribe. This is what causes the same number over and over in the first example.

Defer works something like this:

IObservable<T> Defer(Func<IObservable<T>> factory)
{
    return Observable.Create<T>(obs => factory().Subscribe(obs));
}

so every time you subscribe to the Defer observable, it must call the factory function. In this case, the factory creates a new observable, thus avoiding the caching behavior of Start.

An alternate way to get the sequence you described is to use Interval to get your timing and Select to get the random numbers.

Observable.Interval(TimeSpan.FromMilliseconds(100))
          .Select(i => random.Next())
          .Subscribe(Console.WriteLine);
like image 153
Gideon Engelberth Avatar answered Oct 15 '22 09:10

Gideon Engelberth