2

.Schedule(DateTimeOffset、Action>)のものを使用してRXスケジューラークラスを操作しています。基本的に、私は自分自身を再びスケジュールできるスケジュールされたアクションを持っています。

コード:

public SomeObject(IScheduler sch, Action variableAmountofTime)
{
    this.sch = sch;
    sch.Schedule(GetNextTime(), (Action<DateTimeOffset> runAgain =>
    {
        //Something that takes an unknown variable amount of time.
        variableAmountofTime();

        runAgain(GetNextTime());
    });
}

public DateTimeOffset GetNextTime()
{
    //Return some time offset based on scheduler's 
    //current time which is irregular based on other inputs that i have left out.
    return this.sch.now.AddMinutes(1);
}

私の質問は、variableAmountofTimeにかかる時間をシミュレートし、コードが期待どおりに動作し、期待どおりに呼び出しをトリガーするだけであることをテストすることに関するものです。

デリゲート内でテストスケジューラの時間を進めてみましたが、うまくいきません。私が書いたコードの例は機能しません。GetNextTime()がちょうど1分をスケジュールしていると仮定します。

[Test]
public void TestCallsAppropriateNumberOfTimes()
{
    var sch = new TestScheduler();

    var timesCalled = 0;

    var variableAmountOfTime = () => 
        { 
            sch.AdvanceBy(TimeSpan.FromMinutes(3).Ticks); 
            timescalled++; 
        };

    var someObject = new SomeObject(sch, variableAmountOfTime);

    sch.AdvanceTo(TimeSpan.FromMinutes(3).Ticks);

    Assert.That(timescalled, Is.EqualTo(1));
}

3分先に行きたいのですが、実行に3分かかるので、これを1回だけトリガーしたいのですが、3回トリガーします。

テストスケジューラを使用して、実行中に時間がかかるものをシミュレートするにはどうすればよいですか。

4

1 に答える 1

7

良い質問。残念ながら、これは現在Rxv1.xおよびRxv2.0 Betaではサポートされていません(ただし、読み進めてください)。ネストされたAdvance*呼び出しの複雑さについて説明します。

基本的に、Advance *は、指定されたポイントまで作業を実行するためにスケジューラーを開始することを意味します。これには、仮想スケジューラーの時間の流れを表す単一の論理スレッドで作業を順番に実行することが含まれます。ネストされたAdvance*呼び出しを許可すると、いくつかの疑問が生じます。

まず、ネストされたAdvance *呼び出しにより、ネストされたワーカーループを実行する必要がありますか?その場合、現在の作業項目が中断されて内部ループを実行するため、単一の論理実行スレッドを模倣することはなくなります。実際、Advance *は暗黙のyieldにつながり、Advance *呼び出し後の残りの作業(現在期限が切れている)は、ネストされたすべての作業が処理されるまで実行できません。これは、将来の作業が過去の作業に依存(または待機)して実行を終了できない状況につながります。1つの方法は、実際の物理的な同時実行性を導入することです。これにより、仮想時間のさまざまな設計ポイントと履歴スケジューラーが最初から無効になります。

または、ネストされたAdvance *呼び出しが、最上位のワーカーループディスパッチ呼び出し(Advance *またはStart)と何らかの形で通信する場合、ネストされた呼び出しが元の期限を超えたポイントに進むように要求したため、期限を延長する必要があります。しかし今、あらゆる種類のものが奇妙になっています。Advance *から戻った後の変更は時計に反映されず、最上位の通話は予測可能な時間に終了しなくなります。

Rx v2.0 RC (来月公開)では、このシナリオを検討し、Advance *は、呼び出されたコンテキストによってはオーバーロードされた意味が必要になるため、「タイムスリッページ」をエミュレートするのは適切ではないと判断しました。 。代わりに、実行中の作業の副作用なしに、任意のコンテキストから時間を進めるために使用できるSleepメソッドを導入しています。Clockプロパティを設定する方法として考えてください。ただし、時間を遡らないように保護してください。名前もその意図を明確に反映しています。

上記に加えて、ネストされたAdvance *呼び出しが効果を発揮しないという驚きの要因を減らすために、この状況を検出し、ネストされたコンテキストでInvalidOperationExceptionをスローするようにしました。一方、睡眠はどこからでも呼び出すことができます。

最後に1つ。時間の処理に関して、Rxv2.0RCで行っている作業とまったく同じ機能が必要であることがわかりました。いくつかのテストでは、任意の時間がかかる可能性のあるユーザーコードの実行による時間のずれをエミュレートするための決定論的な方法が必要でした(OnNextハンドラーをObservable.Intervalなどと考えてください)。

これがお役に立てば幸いです...今後数週間のRxv2.0RCリリースにご期待ください!

-バート(Rxチーム)

于 2012-05-28T09:07:26.130 に答える