简体   繁体   English

编程c#:Parallel.Foreach内存消耗管理

[英]Programming c#: Parallel.Foreach Memory Consumption Management

I would like to use the Parallel.Foreach mechanism to ensure full utilisation of the CPU for a CPU-intensive task. 我想使用Parallel.Foreach机制来确保CPU密集型任务的CPU充分利用。 I am querying a significant amount of objects from a database one at a time (only one object within each iteration, each object reasonably small), and then performing a significant amount of CPU-based operations on this object, after which I save it back to the database. 我一次从数据库中查询大量对象(每次迭代中只有一个对象,每个对象相当小),然后对该对象执行大量基于CPU的操作,然后将其保存回去。到数据库。

I am using Entity Framework on the Data Model side, and given the amount of objects that I query I create a new Context for every iteration (this is to limit memory consumption): 我在数据模型侧使用实体框架,并根据查询的对象数量,为每次迭代创建一个新的上下文(这是为了限制内存消耗):

    foreach (var id in idlist)
    {
        using (var ctx = new Context())
        {
            var model = ctx.Models.First(x => x.Id == id);
            await model.GlobalRefresh(true); //CPU heavy operation.
            await model.SaveAsync(); //Additional CPU heavy operation.
            ctx.SaveChanges(); //Save the changes
        } //Dispose of the model and the context, to limit memory consumption
    }

This works well in the synchronous implementation, as after each iteration both the model queried from the database and the Entity Framework context is disposed. 这在同步实现中效果很好,因为在每次迭代之后,都会处理从数据库查询的模型和实体框架上下文。 My memory consumption during this process is therefore almost constant, which is great. 因此,在此过程中我的内存消耗几乎是恒定的,这非常好。 If I don't create the context in this fashion, I quickly run out of memory (500+ objects). 如果不以这种方式创建上下文,则会很快耗尽内存(500多个对象)。

When I set the above up in parallel as follows, my memory consumption goes sky high, as it seems that the context for each iteration is not disposed before the next iteration continues (and I do see significantly better CPU utilisation as expected): 当我按如下所示并行进行上述设置时,我的内存消耗飞速增长,因为似乎每次迭代的上下文在下一次迭代继续之前就没有释放(并且我确实看到了预期的明显更高的CPU利用率):

        Parallel.ForEach(idlist, async (id) =>
        {
            using (var ctx = new Context())
            {
                var model = ctx.Models.First(x => x.Id == id);
                await model.GlobalRefresh(true);
                await model.SaveAsync();
                ctx.SaveChanges();
            }
        });

This is not necessarily a problem from a memory viewpoint, as long as all model objects aren't loaded into memory at once (this is also effectively the whole point of the parallel loop, to load more than one at a time). 从内存的角度来看,这并不一定是问题,只要所有模型对象都不会一次加载到内存中(这实际上是并行循环的整个要点,一次要加载多个)。 However, is there some way that I can manage this process better, eg not creating additional tasks when memory consumption reaches eg 75%, to avoid the Out Of Memory exception? 但是,是否有某种方法可以更好地管理此过程,例如在内存消耗达到75%时不创建其他任务,以避免内存不足异常?

TL;DR: You can use MemoryFailPoint to check for sufficient memory before your next operation. TL; DR:可以在下次操作之前使用MemoryFailPoint检查是否有足够的内存。 Microsoft Docs has a nice example here . Microsoft Docs 在这里有一个很好的例子。

I had a similar issue recently. 我最近有一个类似的问题。 I noticed some "Out of memory exceptions" when I was inspecting the logs for an older app. 在检查较旧应用程序的日志时,我注意到一些“内存不足异常”。 Turns out a developer introduced some Parallel programming to make the app faster. 事实证明,开发人员引入了一些并行编程,以使应用程序更快。 So maybe the app is faster, but it is consuming memory faster now and hitting the memory limit for 32-bit app which is around 2GB, and then having these out of memory exceptions. 因此,也许该应用程序运行速度更快,但现在消耗的内存速度更快,并且达到了32位应用程序内存限制 (约为2GB),然后出现了这些内存不足异常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM