C# 可观测的.fromsync和#x2B的组合;重复+;TakeWhile创建无限循环

C# 可观测的.fromsync和#x2B的组合;重复+;TakeWhile创建无限循环,c#,system.reactive,reactive,C#,System.reactive,Reactive,有人能解释一下为什么下面的AsObservable方法创建了一个无限循环,即使到达了流的末尾 公共静态类StreamExt{ 公共静态IObservable asobbservable(此流,int bufferSize){ 可观测回波 .FromAsync(取消=>stream.ReadBytes(缓冲区大小,取消)) .重复 .TakeWhile(字节=>字节!=null)//EndOfStream .SelectMany(字节=>字节); } 私有静态异步任务ReadBytes(此流、in

有人能解释一下为什么下面的
AsObservable
方法创建了一个无限循环,即使到达了流的末尾

公共静态类StreamExt{
公共静态IObservable asobbservable(此流,int bufferSize){
可观测回波
.FromAsync(取消=>stream.ReadBytes(缓冲区大小,取消))
.重复
.TakeWhile(字节=>字节!=null)//EndOfStream
.SelectMany(字节=>字节);
}
私有静态异步任务ReadBytes(此流、int bufferSize、CancellationToken cancel){
var buf=新字节[bufferSize];
var bytesRead=等待流
.ReadAsync(buf,0,缓冲区大小,取消)
.配置等待(错误);
if(bytesRead<1)返回null;//EndOfStream
var result_size=Math.Min(字节读取,缓冲大小);
调整数组大小(参考buf,结果大小);
返回buf;
}
}
快速测试表明,它会生成一个无限循环:

类程序{
静态void Main(字符串[]参数){
使用(var stream=newmemoryStream(新字节[]{1,2,3})){
var testResult=stream
.AsObservable(1024)
.可计算的()
.ToArray();
Console.WriteLine(testResult.Length);
}
}
}
当然,我可以添加一个
.SubscribeOn(TaskPoolScheduler.Default)
,但是,无限循环保持活动状态(阻止任务池调度器+无限读取

[更新2017-05-09]

Shlomo举了一个更好的例子来重现这个问题:

inti=0;
var testResult=Observable.fromsync(()=>Task.fromsresult(i++))
.重复
.TakeWhile(l=>l<3);
订阅(b=>Console.WriteLine(b),e=>{},()=>Console.WriteLine(“OnCompleted”);
Console.WriteLine(“这从未打印过”);

您可以通过以下方法确认是否正确生成了未完成的

using (var stream = new MemoryStream(new byte[] { 1, 2, 3 }))
{
    var testResult = stream
        .AsObservable(1024)
        ;
    testResult.Subscribe(b => Console.WriteLine(b), e => {}, () => Console.WriteLine("OnCompleted"));
}
看起来
.fromsync
+
.Repeat
组合有问题。以下代码的作用类似:

int i = 0;
var testResult = Observable.FromAsync(() => Task.FromResult(i++))
    .Repeat()
    .TakeWhile(l => l < 3)
    ;
testResult.Subscribe(b => Console.WriteLine(b), e => { }, () => Console.WriteLine("OnCompleted"));
Console.WriteLine("This is never printed.");
inti=0;
var testResult=Observable.fromsync(()=>Task.fromsresult(i++))
.重复
.TakeWhile(l=>l<3)
;
订阅(b=>Console.WriteLine(b),e=>{},()=>Console.WriteLine(“OnCompleted”);
Console.WriteLine(“这从未打印过”);
…鉴于此代码正确终止:

var testResult = Observable.Generate(0, i => true, i => i + 1, i => i)
    .Repeat()
    .TakeWhile(l => l < 3)
    ;
testResult.Subscribe(b => Console.WriteLine(b), e => { }, () => Console.WriteLine("OnCompleted"));
Console.WriteLine("This is printed.");
var testResult=Observable.Generate(0,i=>true,i=>i+1,i=>i)
.重复
.TakeWhile(l=>l<3)
;
订阅(b=>Console.WriteLine(b),e=>{},()=>Console.WriteLine(“OnCompleted”);
Console.WriteLine(“这是打印的”);

Shane Neuville发布了包含此行为解释的链接:


对于来到这里需要答案而不仅仅是解释的任何人:问题似乎是异步
的默认调度程序,如所示。如果您调整到“当前线程”调度程序
Repeat()。TakeWhile(…)
的行为更可预测。例如(问题摘录):


这里有一个
.Repeat()
调用,它“无限期地重复可观察序列”。您想要实现的到底是什么?请阅读
,直到它结束或用户处理其订阅<如果谓词的计算结果为
true
(流结束),则code>TakeWhile
应停止可观察流。目前,即使订阅中的
.Dispose()
也没有停止
.Repeat()
。如果在
.Repeat()
之后调用它,为什么
.TakeWhile()
会停止呢?我确实有一个解决方案(使用
Observable.Create
)。我想了解为什么
Observable.fromsync
+
.Repeat()
组合不起作用。感谢您的测试。
.FromAsync(cancel => stream.ReadBytes(bufferSize, cancel), 
    System.Reactive.Concurrency.Scheduler.CurrentThread)
.Repeat()
.TakeWhile(bytes => bytes != null) // EndOfStream