2011-11-12 2 views
2

Rxについての知識を広げようとしています。だから私はストリームで遊んでいて、彼らが私が期待するように行動させようとしています。Repeat()を使用して非決定論的な結果が得られる理由

OnCompletedと再購読の間の通知を緩める可能性があるため、Repeat()演算子が実際に問題を抱えていると読んだことがありますが、自分自身で次のようなことが起こる理由はわかりません。

結果1:

1 at 1006 
3 at 3007 
5 at 4995 

それはそれはそこに2と4を残しそれでもこの結果内のことを良いことだ、私はこの例を実行すると、結果は完全に非決定的です

 var subject = new Subject<string>(); 

     var my = subject 
      .Take(1) 
      .Merge(Observable.Empty<string>().Delay(TimeSpan.FromMilliseconds(2000))) 
      .Repeat(); 
     my.Subscribe(Console.WriteLine); 

     var stopwatch = new Stopwatch(); 
     stopwatch.Start(); 
     Scheduler.ThreadPool.Schedule(TimeSpan.FromSeconds(1),() => subject.OnNext("1 at " + stopwatch.ElapsedMilliseconds)); 
     Scheduler.ThreadPool.Schedule(TimeSpan.FromSeconds(2),() => subject.OnNext("2 at " + stopwatch.ElapsedMilliseconds)); 
     Scheduler.ThreadPool.Schedule(TimeSpan.FromSeconds(3),() => subject.OnNext("3 at " + stopwatch.ElapsedMilliseconds)); 
     Scheduler.ThreadPool.Schedule(TimeSpan.FromSeconds(4),() => subject.OnNext("4 at " + stopwatch.ElapsedMilliseconds)); 
     Scheduler.ThreadPool.Schedule(TimeSpan.FromSeconds(5),() => subject.OnNext("5 at " + stopwatch.ElapsedMilliseconds)); 
     Scheduler.ThreadPool.Schedule(TimeSpan.FromSeconds(6),() => subject.OnNext("6 at " + stopwatch.ElapsedMilliseconds)); 

     Console.ReadLine(); 

実際には3と5の間に実際の2秒のギャップがないので、いくらか違和感があります。

しかし、結果はさらに悪化する可能性があります。この1つを参照してください:

1 at 1003 
2 at 2003 
4 at 4005 
6 at 6004 

1から2の間に2秒のギャップはありません。ちょうど1秒です。なぜ彼はそれを放棄していないのですか?

誰かが私のことを明確にすることができたら、私はもっと幸せになるでしょう!

EDIT

は、私はちょうどそれがここで間違っているマージかもしれないことに気づきました。私は、連結方式に私のクエリをリファクタリングした場合、物事は、彼らが必要として起こるように見える:

 var my = subject 
      .Take(1) 
      .Concat(Observable.Empty<string>().Delay(TimeSpan.FromMilliseconds(2000))) 
      .Repeat(); 

答えて

1

のWindows(および他のデスクトップのOS)実行時のOSではありませんので、あなたはそのタイマーはミリ秒単位まで正確になることを頼ることはできません。特にタイマーが多い場合、これは非決定論的な動作につながる可能性があります。これはまさにあなたのケースです。

これはあなたの元のシーケンスがどのように動作するかです:〜1

  • 時間が刻々と過ぎて遅れて空に観察開始のためのsubject
  • タイマへ〜0
    • Take(1)購読

      • 時間を
        • 1が加えられる。 subject、1が書き出されます。この時点の後、誰もがsubjectに加入していないもう
      • 時間が観測遅れ空のために〜2
        • タイマーが切れます。そのため、Take(1)再びsubjectに加入すると遅延空に観察開始ほぼ同時に
        • のための別のタイマーは、2は、subjectため、タイミングのわずかな違いの

      に2つのアクションを追加します時間約。 2は任意の順序で起こり得る。そして、注文は重要です。Take()の前に2が追加されます。したがって、2を書き出すことができます。

      何をしたいことは、このようなシーケンスである場合:最初のアイテムを待つ

      1. それを返す2番目の項目のために約2秒
      2. 待ち時間を待って(追加されたそのいずれかを無視してそれを返します2秒の待ち時間)
      3. 中...

      その後、私はあなたの編集中のコードが正しいと思います。

      しかし、これは決定的な結果を保証するものではありません。私のコンピュータ上で、遅延空の観測値の待ち時間を1960ミリ秒に変更すると、Concat()を使用すると非確定的な結果が得られます。

  • 0

    私の2cをパーティーに遅れて追加するだけです。テストのための決定論を探しているなら、実際のThreadPool/TaskPool/NewThreadスケジューラーの代わりにTestSchedulerを使うべきです。純粋にSvickが指摘する理由(OSスケジューリングはボートを揺るがす)。

    関連する問題