使用System.Reactive重置计时器

时间:2017-06-23 20:16:46

标签: c# system.reactive reactive-programming

我想使用IObservable.Timeout()来检测数据源是否已“脱机”。此数据源是在循环内读取的串行连接。

读操作是故意阻塞的,如果我在预定义的时间内没有收到任何数据,我想取消操作。否则,每次我收到数据时,我都希望超时可观察量生成一个项目,从而重置超时。

我的怀疑是以下评论的形式:

void Run()
{
    IObservable<object> timeoutWatcher = CreateResettableTimer();

    timeoutWatcher.Timeout(TimeSpan.FromSeconds(1)).Subscribe(_cancellation.Cancel());

    while (!_cancellation.IsCancellationRequested)
    {               
        var frameVals = FTDIHelper.ReadAvailableBytes(_handle, 8); // blocking;

        DoSomethingWith(frameVals);

        // ??? How do I "add" an item to timeoutWatcher ???
    }
}

IObservable<object> CreateResettableTimer()
{
    // ??? What should I return, and how to create it ??? 
    // Use a Subject? If not, what else then?
    // Should it be returning IObservable<object> or other type?
}

1 个答案:

答案 0 :(得分:2)

您可以使用Timeout运算符为可在指定时间内未生成值的observable指定超时(这具有语义意义)。超时传播您可以订阅的OnError - 这确实会导致超时管道被拆除,但您可以使用Retry来应用重新订阅逻辑。使用OnError应用取消逻辑。您还可以通过同一个管道处理非超时错误。

这是一个模拟任务的示例&#39;需要花费一段时间才能完成,如果超过两秒钟就会检测到超时。

var randomSource =
    Observable.Defer(() => Observable.Timer(TimeSpan.FromSeconds(new Random().NextDouble() * 5))).Repeat().Publish(); 

randomSource
    .Do(v => Console.WriteLine(DateTime.Now))
    .Timeout(TimeSpan.FromSeconds(2)) 
    .Do(_ => { }, err => Console.Write("\t\t\tTimed out\r")) //on error callback
    .Retry()
    .Subscribe(); //set up the pipeline

randomSource.Connect();

Console.ReadLine();

输出:

6/26/2017 7:15:42 PM    Timed out
6/26/2017 7:15:43 PM
6/26/2017 7:15:46 PM    Timed out
6/26/2017 7:15:47 PM
6/26/2017 7:15:51 PM    Timed out
6/26/2017 7:15:56 PM    Timed out
6/26/2017 7:16:00 PM    Timed out
6/26/2017 7:16:02 PM
6/26/2017 7:16:02 PM
6/26/2017 7:16:05 PM    Timed out
6/26/2017 7:16:06 PM
6/26/2017 7:16:08 PM
6/26/2017 7:16:08 PM
6/26/2017 7:16:10 PM
6/26/2017 7:16:13 PM    Timed out
6/26/2017 7:16:18 PM    Timed out

如您所见,任何超过两秒的时间都会超时。