我完全不知道这件事。只在Rx工作了几天而且很明显我的理解中存在一个基本的例外。所以在根据各种文章尝试了很多想法后,我需要一些专家的眼睛来指出我是什么&#39我没有看到......
我正在尝试测试一些模拟轮询机制的代码。我正在使用Microsoft.Reactive.Testing TestScheduler来提供一个"虚拟时间线"我可以推进时间表,以便在很长一段时间内快速模拟大量民意调查......确实非常有用:
var scheduler = new TestScheduler();
// create the sequence of polls (each poll returns a string)
var observeable = poller.CreatePollingSequence(scheduler);
observeable.Subscribe(
item =>
{
Debug.WriteLine(item));
},
_ => Debug.WriteLine("Completed!"));
scheduler.AdvanceBy(60*1000* TimeSpan.TicksPerMillisecond);
这是CreatePollingSequence的实现。 Note" PollResult"是一个简单的类,它包含一个表示轮询返回的行数的字符串列表。例如PollResult(1)生成一个包含一个文本字符串的结果。
public IObservable<PollResult> CreatePollingSequence(IScheduler scheduler)
{
return Observable.Create<PollResult>(
(IObserver<PollResult> observer) =>
{
return scheduler.ScheduleAsync(async (sched, ct) =>
{
Observable.Timer(TimeSpan.FromSeconds(0), scheduler)
.Subscribe(_ =>
{
observer.OnNext(new PollResult(1));
});
await sched.Yield();
observer.OnCompleted(); // end of sequence
return Disposable.Empty;
});
});
}
所以这一切似乎都运转正常(虽然我不完全确定在我的Rx旅程中此时某些线路的基本原理,甚至整体正确性......)。
但这是关键问题:当我将ObserveableTimer的offsetTime参数更改为非零值时(为了模拟时间 dueOffsetTime 的初始轮询),事情开始误入歧途。具体来说,订阅 CreatePollingSequence 返回的序列的代码突然永远不会执行。要重新迭代, 它会在Timer序列的OffsetTime参数为零时执行 。从代码中可以看出,我已经开始怀疑当Timer返回的序列在除了立即之外的任何其他时间生成时,这可能是调度程序上的某种形式的死锁...因此出现.Yield和使用ScheduleAsync ......但我敏锐地意识到我没有发现实际问题,所以我不能确定解析代码应该是什么。因此这个问题 - 希望有人能指出错误的原因......非常感谢提前。
答案 0 :(得分:0)
我不完全确定CreatePollingSequence
应该做什么,但我认为这样做更简洁,适用于非零offsetTime:
public IObservable<PollResult> CreatePollingSequence(IScheduler scheduler)
{
return Observable.Timer(TimeSpan.FromSeconds(1), scheduler)
.Select(_ => new PollResult(1));
}
编辑:
在回答您的问题时,您无需明确致电observer.OnNext
。 Observable.Timer
会为您做到这一点。我建议您尝试替换我的代码。
Rx包围IObservable
和IObserver
的方式与LINQ包围IEnumerable
和IEnumerator
(或者IQueryable
)的方式非常相似。在LINQ-land中,如果你直接调用enumerater.MoveNext()
,你可能做错了:LINQ的全部意义是利用Enumerable monad的灵活性/可兼容性,所以你要相对调用高级,可链接的函数(LINQ运算符)。
与Rx类似,目标是尽可能使用Rx运算符,并避免直接调用Observer或调度程序方法。你可以使它工作,维护,阅读,支持等更难。如果我正在审查你的代码,我会引用以下问题:
Observable.Create
非常类似于实现您的observable,您希望避免这样做。 Observable.Timer
订阅),但没有处置或跟踪该订阅。这可能会导致内存泄漏。总之,使用简单的代码。它使小猫高兴。
答案 1 :(得分:0)
最后解决了这个问题。我认为!这是一个简单的愚蠢错误。我把observer.OnCompleted()调用在错误的地方,事实上它根本就没有被调用过。它应该是Observeable.Timer.Subscribe的第二个参数(参见下面的代码)。 ScheduleAsync也是多余的。
public IObservable<PollResult> CreatePollingSequence(IScheduler scheduler)
{
return Observable.Create<PollResult>(
(IObserver<PollResult> observer) =>
{
return scheduler.ScheduleAsync(async (sched, ct) =>
{
Observable.Timer(TimeSpan.FromSeconds(1), scheduler)
.Subscribe(_ =>
{
// make this configurable...i.e actual data returned!!!
// GetData();
observer.OnNext(new PollResult(2));
}, () => observer.OnCompleted());
return Disposable.Empty;
});
});
}