我在项目列表上执行的任务很慢。 这就是我想要实现的目标:
这是我的原型 - 它按预期工作(LinqPad)
async Task Main()
{
int throttle = 3;
var result =
Enumerable.Range(1, 20)
.ToObservable()
.Select(n => Observable.FromAsync(() => DoSomething(n)))
.Merge(throttle)
.Replay();
Task.Run(async () => await result);
Util.KeepRunning();
}
public async Task DoSomething(int n)
{
Console.WriteLine($"Starting {n}");
await Task.Delay(100);
Console.WriteLine($"Ending {n}");
}
这是我的实际代码:
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和没有
用假负载替换项目加载器
有和没有_maxConcurrent
这段代码在等待中永远挂起,我似乎无法看到与原型在功能上有什么不同。
如果我删除重播,代码会按预期运行,但会被每个订阅者点击。
有没有人知道这段代码是如何不同的,以及为什么Replay方法会影响这样的执行?
我开始怀疑它必须是订阅者的问题 - 但目前我无法轻易提取这些内容以进行验证。
以下是可行的原始代码(但不会扼制)
sln.Projects = result.Projects
.Select(p => projectLoader.Load(p, sln))
.ToList()
.Select(p => p.ToObservable())
.Merge();
答案 0 :(得分:0)
原型与实际使用代码之间的区别在于存储observable的方式。在您的原型中,它存储为局部变量,但在您的生产代码中,您将其保留在sln
对象中。
为了能够为将来的订阅者重放观察中的所有信号,它无法完成。我认为它与局部变量一起使用的原因与局部范围有关,但我还没有挖掘它。
如果在Linqpad中运行以下命令,您将看到将observable存储在对象中会改变行为。
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; }
}
Replay()
会返回IConnectableObservable
,为了生成此可观察的返回值,您必须在其上调用Connect()
。这样做使上面的代码适合我:
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; }
}