2

Rxに関する知識を広げようとしています。ですから、私はストリームをいじって、期待どおりに動作させるようにしています。

OnCompletedと再サブスクリプションの間の通知が失われる可能性があるため、Repeat()演算子は実際には困難であると読んだことがありますが、次のことがなぜ発生するのかを自分で理解することはできません。

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

この例を実行すると、結果は完全に非決定論的です。

結果1:

1 at 1006
3 at 3007
5 at 4995

2と4を省略したのは良いことですが、実際には3と5の間には実際の2秒のギャップがないため、この結果の内部でも奇妙なことがあります。

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

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

1と2の間に2秒のギャップはありません。正確に1秒です。なぜ彼はそれを省かなかったのですか?

誰かが私のために物事を明確にすることができれば、私は幸せ以上になります!

編集

ここで間違っているのはマージである可能性があることに気づきました。クエリをConcatにリファクタリングすると、次のようになります。

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

2 に答える 2

1

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

これが元のシーケンスの仕組みです。

  • 時間〜0
    • Take(1)購読するsubject
    • 遅延した空のオブザーバブルのタイマーがカチカチ音をたて始めます
  • 時間〜1
    • 1がに追加されsubject、1が書き出されます。この時点以降、誰もサブスクライブしsubjectなくなります
  • 時間〜2
    • 遅延した空のオブザーバブルのタイマーが切れます。そのため、再度Take(1)サブスクライブし、subject空の監視可能な開始を遅らせるための別のタイマー
    • ほぼ同時に、2に追加されますsubject

タイミングのわずかな違いのため、時間の2つのアクションは約。2は任意の順序で発生する可能性があります。そして、順序は重要Take()です。再サブスクライブの前または前に2が追加されます。したがって、2を書き出すこともできません。

必要なのが次のようなシーケンスの場合:

  1. 最初のアイテムを待って、それを返します
  2. 約2秒待ちます
  3. 2番目のアイテムを待って、それを返します(2秒間の待機中に追加されたものは無視します)
  4. …</li>

それならあなたの編集のコードは正しいと思います。

しかし、これは決して決定論的な結果を保証するものではありません。私のコンピューターで、遅延された空のオブザーバブルの待機時間を1960ミリ秒に変更すると、を使用したときに非決定論的な結果が得られConcat()ます。

于 2011-11-12T13:05:20.593 に答える
0

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

于 2013-04-24T15:21:41.830 に答える