简体   繁体   English

如何使用Reactive Extensions(Rx.Net)等待一个值或直到经过一段固定的时间

[英]How to wait for a value or until a fixed amount of time has elapsed using Reactive Extensions (Rx.Net)

I want to wait (block) a thread until either a time has elapsed or another stream pumps a value, I thought the following might achieve this but it throws an exception because the first stream is empty, 我想等待(阻塞)一个线程,直到时间已经过去或另一个流泵出一个值,我认为以下可能会实现这一点,但它会引发异常,因为第一个流是空的,

 // class level subject manipulated by another thread...
 _updates = new Subject<Unit>();
 ...
 // wait for up to 5 seconds before carrying on...    
 var result = Observable.Timer(DateTime.Now.AddSeconds(5))
    .TakeUntil(_updates)
    .Wait();

How can I achieve the ability to block for up to 5 seconds or until the other stream pumps a value? 如何实现阻止最多5秒或直到另一个流泵出值的能力?

You can use Observable.Timeout like this: 您可以像这样使用Observable.Timeout

 var result = _updates.Take(1).Timeout(DateTime.Now.AddSeconds(5)).Wait();

I use Take(1) because timeout expects sequence to complete, not just produce next value. 我使用Take(1)因为timeout需要序列完成,而不仅仅是产生下一个值。 On timeout it will throw System.TimeoutException . 在超时时,它将抛出System.TimeoutException

If you don't want exception - you can use Catch to provide some value instead: 如果您不想要例外 - 您可以使用Catch来提供一些值:

var result = _updates.Take(1).Timeout(DateTime.Now.AddSeconds(5))
    .Catch(Observable.Return(default(Unit))).Wait();
// should catch specific exception, not all

If your Unit is indeed that rx unit mentioned by @Shlomo - you can change it like this: 如果您的Unit确实是@Shlomo提到的rx单位 - 您可以像这样更改它:

var result = _updates.Select(c => (Unit?) c).Take(1)
    .Timeout(DateTime.Now.AddSeconds(5)).Catch(Observable.Return((Unit?) null)).Wait();

or just catch that exception as usual. 或者像往常一样抓住那个例外。

Here's another alternative if you don't want to deal with exceptions: 如果您不想处理异常,这是另一种选择:

var _updates = new Subject<Unit>();

var result = Observable.Merge(
    _updates.Materialize(),
    Observable.Empty<Unit>()
       .Delay(TimeSpan.FromSeconds(5))
       .Materialize()
   )
   .Take(1)
   .Wait();

switch (result.Kind)
{
    case NotificationKind.OnCompleted:
        //time's up, or someone called _updates.OnCompleted().
        break;
    case NotificationKind.OnNext:
        var message = result.Value;
        //Message received. Handle message
        break;
    case NotificationKind.OnError:
        var exception = result.Exception;
        //Exception thrown. Handle exception
        break;
}

Can you create two tasks and then do a wait any? 你能创建两个任务然后再等待吗? That would likely be the "easiest" way to achieve that. 这可能是实现这一目标的“最简单”方式。

var waitTask = new Task(() => Thread.Sleep(5000));
var messageTask = new Task(() => <listen for input and return>);

await Task.WhenAny(waitTask, messageTask);

<the rest of your code>

Edit: Title changed to specify React, answer probably wouldn't be applicable anymore. 编辑:标题已更改为指定React,答案可能不再适用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM