繁体   English   中英

Take(1) from a Select() on a hot observable

[英]Take(1) from a Select() on a hot observable

我想要做的是有一个热的可观察对象,然后通过 Select 从中派生另一个可观察对象。

接下来我想使用await Take(1)从派生的 observable 中获取单个值,然后订阅它。

int i = 1;
var o1 = Observable
    .Interval(TimeSpan.FromSeconds(1))
    .Select(x => { i++;return i; })
    .Publish()
    .RefCount()
    .Do(x => Console.WriteLine($"emit {x}"));

var o2 = o1.Select(x => x + 5);

await o2.Take(1);
Console.ReadLine();

using (o2.Subscribe(x =>
 {
     Console.WriteLine($"output {x}");
 }))
{
    Console.WriteLine($"subscrbied");
    Console.ReadLine();
}
Console.ReadLine();

但是,我看到的是在await Take(1)之后,可观察对象不再“工作”(不再打印“emit x”)。

为什么是这样?

编辑

有趣的是,如果我添加一个Task.Delay它可以工作:

var o2 = o1.Select(x => x + 5);

await o2.Take(1);
await Task.Delay(1);
Console.ReadLine();

.Publish().RefCount()组合可能有点讨厌。 有时订阅者 go 为零,无法重新订阅查询。

但是,在这种情况下,似乎存在我尚未完全弄清楚的竞争条件。

以下是如何使您的代码工作:

await o2.Take(1).ObserveOn(Scheduler.Default);

ObserveOn的添加允许它以您期望的方式运行。

您使用await Task.Delay(1); 做了同样的事情。 但是为什么仍然让我感到困惑。

最后,忽略使它起作用的杂物,它似乎起作用的唯一原因是您使用的是外部 state int i = 1; . 您可以删除.Publish().RefCount() ,它仍然可以按预期工作。 你应该避免这种外部 state 并且如果你使用它你应该使用Interlocked.Increment(ref i)而不是i++


根据我们的讨论,这是获得所需内容的另一种方法:

var subject = new ReplaySubject<long>(1);
var source = Observable.Interval(TimeSpan.FromSeconds(1.0));
var subscription = source.Subscribe(subject);
Thread.Sleep(TimeSpan.FromSeconds(4.5));
var z = await subject.Take(1);
Console.WriteLine($"0:{z}z");
Thread.Sleep(TimeSpan.FromSeconds(2.5));
subject.Take(5).Subscribe(x => Console.WriteLine($"1:{x}x"));
Thread.Sleep(TimeSpan.FromSeconds(2.5));
subject.Take(5).Subscribe(x => Console.WriteLine($"2:{x}x"));

暂无
暂无

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

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