BFree
BFree

Reputation: 103740

Observable.Generate not generating as quick as I'd expect. What am I missing?

Given the following RX code:

    static void Main(string[] args)
    {
        int x = 0;
        const int timerMilliseconds = 1000 * 30; //30 seconds
        var disposable = Observable.Generate(0, i => true, i => 1, i => 1, i => TimeSpan.FromMilliseconds(1))
            .Subscribe(i => Interlocked.Increment(ref x));

        var timer = new Timer(o =>
                                  {
                                      disposable.Dispose();
                                      Console.WriteLine("Disposed of observable. Current total: " + x);
                                  }, null, timerMilliseconds, timerMilliseconds);


        Console.ReadKey(true);
        timer.Dispose();
    }

If I run this code, the output after 30 seconds (on my machine) is ~1924, which is kind of surprising to me. I would have expected that with a delay of one millisecond, after 30 seconds the number should be closer to ~30,000. It must be something obvious, but what am I missing here?

Upvotes: 1

Views: 197

Answers (2)

Chris Shain
Chris Shain

Reputation: 51329

@afrischke is right. It appears to be related to the use of a System.Timers.Timer behind the scenes to schedule the Generations when you don't specify another Scheduler. Initially, I got the same results as you, and I noted in particular that it was not generating any sort of measurable CPU activity. When I change the code to the following, I (probably not surprisingly) get a significantly larger number:

var generator = Observable.Generate(0, i => true, i => 1, i => 1, i => TimeSpan.FromTicks(1));
var disposable = generator.Subscribe(i => Interlocked.Increment(ref x));

I think that what is happening is that the Observable is obeying the letter of the law- it is scheduling the next Generation for at least a millisecond away, but no sooner. In practice, this turns out to actually be more like 10ms away.

Upvotes: 2

afrischke
afrischke

Reputation: 3866

I think you are forgetting that the Windows operating system doesn't give you a hard guarantee that the generating and/or observing thread will be scheduled to run within the next millisecond. Depending on the state of your system some overhead wrt to context switching might be involved as well. On my rusty old laptop I didn't manage to get below ~20 ms. (I measured the time between invocations of the "Subscribe" lambda with the help of a Stopwatch.)

Upvotes: 4

Related Questions