C# 为什么重播方法会阻止可观察集合的完成?
我有一个运行缓慢的任务要在项目列表上执行。 这就是我想要实现的目标:C# 为什么重播方法会阻止可观察集合的完成?,c#,roslyn,rx.net,C#,Roslyn,Rx.net,我有一个运行缓慢的任务要在项目列表上执行。 这就是我想要实现的目标: 应立即开始处理 最多N个并发任务 每个项目只能运行一次任务 所有订阅者都应该看到所有结果(无论他们何时订阅) 这是我的原型机-它按预期工作(LinqPad) 这是我的实际代码: sln.Projects = result .Projects .ToObservable() //Appears to be unnecessary .Select(p => Observ
sln.Projects = result
.Projects
.ToObservable() //Appears to be unnecessary
.Select(p => Observable.FromAsync(() => projectLoader.Load(p, sln)))
.Merge(_maxConcurrent)
.Replay();
await sln.Projects; //Hangs forever if Replay is used
“结果”是Microsoft.CodeAnalysisSolution
我尝试了几种变体-Projects.ToList,带ToObservable和不带
用虚拟加载替换了项目加载程序
使用和不使用\u maxConcurrent运行 这段代码在等待时永远挂起,我似乎看不出与原型在功能上有什么不同 如果我删除重播,代码将按预期运行,但每个订阅者都会被命中 有人知道这段代码有什么不同,以及重播方法为什么会影响这样的执行吗 我开始怀疑这一定是订阅者的问题——但这不是我目前可以轻易提取出来验证的东西 下面是可以工作的原始代码(但不起作用)
原型与您实际使用代码之间的区别在于您存储可观察数据的方式。在原型中,它存储为局部变量,但在生产代码中,它保存在
sln
对象中
为了能够为未来的用户重放可观察到的所有信号,它无法完成。我认为它使用局部变量的原因与局部作用域有关,但我还没有深入研究
如果在Linqpad中运行以下命令,您将看到在对象中存储可观察对象会改变行为
async Task Main()
{
int throttle = 3;
var container = new Container();
container.Results =
Enumerable.Range(1, 20)
.ToObservable()
.Select(n => Observable.FromAsync(() => DoSomething(n)))
.Merge(throttle)
.Replay();
var res = await container.Results;
res.Dump("Res");
}
public async Task DoSomething(int n)
{
Console.WriteLine($"Starting {n}");
await Task.Delay(100);
Console.WriteLine($"Ending {n}");
}
public class Container
{
public IObservable<Unit> Results { get; set; }
}
sln.Projects = result.Projects
.Select(p => projectLoader.Load(p, sln))
.ToList()
.Select(p => p.ToObservable())
.Merge();
async Task Main()
{
int throttle = 3;
var container = new Container();
container.Results =
Enumerable.Range(1, 20)
.ToObservable()
.Select(n => Observable.FromAsync(() => DoSomething(n)))
.Merge(throttle)
.Replay();
var res = await container.Results;
res.Dump("Res");
}
public async Task DoSomething(int n)
{
Console.WriteLine($"Starting {n}");
await Task.Delay(100);
Console.WriteLine($"Ending {n}");
}
public class Container
{
public IObservable<Unit> Results { get; set; }
}
async Task Main()
{
int throttle = 3;
var container = new Container();
container.Results =
Enumerable.Range(1, 20)
.ToObservable()
.Select(n => Observable.FromAsync(() => DoSomething(n)))
.Merge(throttle)
.Replay();
container.Results.Connect();
(await container.Results).Dump("1");
(await container.Results).Dump("2");
}
public async Task DoSomething(int n)
{
Console.WriteLine($"Starting {n}");
await Task.Delay(100);
Console.WriteLine($"Ending {n}");
}
public class Container
{
public IConnectableObservable<Unit> Results { get; set; }
}