【发布时间】:2017-04-09 23:36:02
【问题描述】:
我有一小段代码可以模拟使用大型对象(即巨大的byte[])的流程。对于序列中的每一项,都会调用一个异步方法来获得一些结果。问题?事实上,它会抛出OutOfMemoryException。
与 LINQPad(C# 程序)兼容的代码:
void Main()
{
var selectMany = Enumerable.Range(1, 100)
.Select(i => new LargeObject(i))
.ToObservable()
.SelectMany(o => Observable.FromAsync(() => DoSomethingAsync(o)));
selectMany
.Subscribe(r => Console.WriteLine(r));
}
private static async Task<int> DoSomethingAsync(LargeObject lo)
{
await Task.Delay(10000);
return lo.Id;
}
internal class LargeObject
{
public int Id { get; }
public LargeObject(int id)
{
this.Id = id;
}
public byte[] Data { get; } = new byte[10000000];
}
似乎它同时创建了所有对象。我怎样才能以正确的方式做到这一点?
基本思想是调用 DoSomethingAsync 以便为每个对象获取一些结果,这就是我使用 SelectMany 的原因。为了简化,我只是引入了一个Task.Delay,但在现实生活中它是一个可以同时处理一些项目的服务,所以我想引入一些并发机制来利用它。
请注意,理论上,一次处理少量项目不应该填满内存。实际上,我们只需要每个“大对象”来获取 DoSomethingAsync 方法的结果。在那之后,不再使用大对象。
【问题讨论】:
-
我不知道你的问题是你的测试代码(
Enumerable.Range急切地创建所有大对象),还是你在生产中看到这个?无论哪种方式,如果某个序列创建了许多 LargeObjects 并且它们仍在使用中,所以不能被 GC 处理,那么是的,你会得到一个 OOM 异常。
标签: c# .net system.reactive reactive-programming