[英]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.