小问题 - 这个代码是惯用的Rx还是没有 - 如果没有,应该改变什么呢?注意 - 代码在LINQPad中用于测试目的,以后可能用作"样板":
IObservable<byte[]> GenerateRandomDataChunks(IScheduler scheduler, int chunkSize = 10)
{
return
Observable.Create<byte[]>(
observer => {
var cancel = new CancellationDisposable();
scheduler.Schedule(() => {
try // outer capture of exceptions => OnError
{
var rnd = new Random();
while (!cancel.Token.IsCancellationRequested) // => cancellation
{
scheduler.Yield();
var ms = rnd.Next(100, 500);
Thread.Sleep(ms); // introduce artificial lag for testing purposes
//scheduler.Sleep(TimeSpan.FromMilliseconds(ms)); // test simulation doesn't work - why not?
var data = new byte[chunkSize];
rnd.NextBytes(data);
//var r = rnd.Next();
//if (r > 450 && r < 460)
// throw new Exception("foobar");
observer.OnNext(data); // give back next computed value => OnNext
}
observer.OnCompleted(); // terminated naturally => OnCompleted
}
catch (Exception ex)
{
observer.OnError(ex); // handle exception => OnError
}
finally
{
// TODO dispose any resources we might have
}
});
return cancel;
}
);
}
取消似乎很有效。出于测试目的,我尝试插入延迟时间,但它没有使用IScheduler.Sleep(示例ThreadPoolScheduler)。
答案 0 :(得分:2)
您可以像这样使用Observable.Generate
。请注意,在此变体和下一个变量中,如果没有提供调度程序,则提供调度程序,并且按顺序(以及更加惯用)的方式更改调度程序的最后顺序:
IObservable<byte[]> GenerateRandomDataChunks(
int chunkSize = 10, IScheduler scheduler = null
{
var rnd = new Random();
return Observable.Generate<object,byte[]>(
null, _ => true, _ => _, _ => {
var data = new byte[chunkSize];
rnd.NextBytes(data);
return data;
},
// delete next line entirely to remove lag
_ => TimeSpan.FromMilliseconds(rnd.Next(100, 500)),
scheduler ?? Scheduler.Default);
}
您遵循的方法也可以起作用,但需要整理一下。您不需要OnComplete或OnError。处理订阅仅表示OnNext呼叫应该停止。 async / await语法也使事情变得更清晰,并为您提供与订阅生命周期相关的取消令牌。这是由Observable.Create为您处理的。你绝对不想打电话给Thread.Sleep
- 虽然我很感激这是为了测试 - 我在下面显示了Scheduler.Sleep
的正确用法。
IObservable<byte[]> GenerateRandomDataChunks(
int chunkSize = 10, IScheduler scheduler = null)
{
var rnd = new Random();
scheduler = scheduler ?? Scheduler.Default;
return Observable.Create<byte[]>(async (o, ct) => {
while(!ct.IsCancellationRequested)
{
var ms = rnd.Next(100, 500);
await scheduler.Sleep(TimeSpan.FromMilliseconds(ms), ct);
// replace the above with this to yield instead of lag
// await scheduler.Yield(ct);
ct.ThrowIfCancellationRequested();
var data = new byte[chunkSize];
rnd.NextBytes(data);
o.OnNext(data);
}
});
}