如何等待可观察对象完成?

时间:2020-05-10 15:21:59

标签: .net f# reactive-programming system.reactive

在Node.js中,您可以设置服务器,只要该服务器在事件循环中处于活动状态并处于活动状态,该过程就不会终止。我想知道是否可以使用反应式扩展做类似的事情?我知道如何设置命名管道并利用它在另一个进程中与Node服务器通信,但是我不确定如何通过等待按键来阻止程序终止。我想将该服务器实现为反应式管道的一部分。在管道完成之前是否可以阻塞主线程?

2 个答案:

答案 0 :(得分:0)

open System
open System.Threading
open FSharp.Control.Reactive

module Observable = 
    /// Blocks the thread until the observable completes. 
    let waitUnit on_next (o : IObservable<_>) =
        use t = new ManualResetEventSlim()
        use __ = Observable.subscribeWithCompletion on_next (fun _ -> t.Set()) o
        t.Wait()

Observable.interval (TimeSpan.FromSeconds(1.0))
|> Observable.take 3
|> Observable.waitUnit (printfn "%i...")

printfn "Done."

上面使用的是F# Rx bindings,但是C#版本将类似。库本身具有Observable.wait类型的IObservable<'a> -> 'a,但是它的缺点是在空序列上引发异常,并在内存中保留最新值,直到可观察的对象被处置为止。如果最终值不重要,则这具有正确的语义。

我已经看过内部,wait使用ManualResetEventSlim来阻止它所在的线程,所以应该没事。

答案 1 :(得分:0)

对不起,但是我无法在F#中给出答案,但是在C#中,这非常简单。

如果我有这个示例:

Observable
    .Range(0, 10)
    .Subscribe(x => Console.WriteLine(x));

...我想等到它完成,我可以这样重写它:

    Observable
        .Range(0, 10)
        .Do(x => Console.WriteLine(x))
        .ToArray()
        .Wait();

...或:

    await Observable
        .Range(0, 10)
        .Do(x => Console.WriteLine(x))
        .ToArray();

正如Marko在评论中指出的那样,这种方法创建的数组可能很大。为了解决这个问题,您可以将.ToArray()替换为.LastAsync()(在一般使用Async之前用它来表示Task的名称-在这种情况下,它仅返回的最后一个元素可观察为IObservable<T>)。

.Wait()确实抛出了一个空的可观察对象,但是await版本却没有。