2012-02-01 12 views
1

:私はこのコードを実行した場合Observable.Generateは私が期待しているほど速く生成しません。私は何が欠けていますか?以下RXコードが与えられ

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

は、(私のマシンで)30秒後に出力されます〜1924年、私に優しいのは驚くべきことです。 30ミリ秒後に1ミリ秒の遅れで、その数は〜30,000に近づくはずです。それは明白なものでなければなりませんが、私はここで何が欠けていますか?

+0

OnNextへのすべての呼び出しは直列化されているはずです...同時ではありません...したがって、Subscribe OnNextアクション内でInterlocked.Incrementを使用する必要はありません。 –

+0

@RichardHein良い点。このサンプルを、私が作業していたコードの大部分からリッピングしました。そこでは、観察可能なストリームがいくつか同時に実行されていて、すべて同じ変数にアクセスしています。しかし、良いキャッチ。 – BFree

答えて

4

私は、Windowsオペレーティングシステムでは、生成スレッドまたは観測スレッドが次のミリ秒以内に実行するようにスケジュールされていることを強く保証していないことを忘れていると思います。システムの状態によっては、コンテキスト切り替えに対するオーバーヘッドが関係する可能性があります。私の錆びた古いノートパソコンでは、20ミリ秒以下になることはありませんでした。 (私はStopwatchの助けを借りて "サブスクリプション"ラムダの呼び出しの間の時間を測定しました)

2

@afrischkeが正しいです。他のスケジューラを指定していないときに世代をスケジュールするために、舞台裏でSystem.Timers.Timerを使用することに関連しているようです。当初、私はあなたと同じ結果を得ました。特に、私はそれが何らかの種類の測定可能なCPUアクティビティを生成していないことに注意しました。私は何が起こっていることは観察可能で、それがスケジュールされlaw-の手紙に従っていることだと思い

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

:私は次のようにコードを変更すると、私は(おそらく驚くことではない)かなり大きな数を取得します次世代のは少なくともミリ秒離れていますが、すぐにはありません。実際には、これは実際には10msほど離れているようです。