c# – 任务并行库中的BlockingCollection不会自动释放基础实例的引用

c# – 任务并行库中的BlockingCollection不会自动释放基础实例的引用,第1张

概述我使用BlockingCollection在C#4.0中实现生产者 – 消费者模式. BlockingCollection包含占用大量内存的项目.我想让生产者一次从BlockingCollection中取出一个项目并进行处理. 我想通过在BlockingCollection.GetConsumingEnumerable()上使用foreach,每次,BlockingCollection将从底层队列 我使用BlockingCollection在C#4.0中实现生产者 – 消费者模式.

BlockingCollection包含占用大量内存的项目.我想让生产者一次从BlockingCollection中取出一个项目并进行处理.

我想通过在BlockingCollection.GetConsumingEnumerable()上使用foreach,每次,BlockingCollection将从底层队列中删除该项(这意味着所有与引用一起),因此在Process()方法的末尾处理项目,该项目可以被垃圾收集.

但是这是错误的.似乎BlockingCollection.GetConsumingEnumerable()上的foreach循环确实包含输入到队列中的项的所有引用.所有物品都被保持(因此防止被垃圾收集)直到踩出foreach循环.

我没有在BlockingCollection.GetConsumingEnumerable()上使用简单的foreach循环,而是使用while循环测试BlockingCollection.IsComplete标志并在循环内部使用BlockingCollection.Take()来获取耗材.我假设BlockingCollection.Take()具有与List.Remove()类似的效果,它将从BlockingCollection中删除该项的引用.但这又是错误的.所有项目仅在while循环之外收集垃圾.

所以我的问题是,我们如何轻松实现这一要求,以便BlockingCollection可能会占用内存消耗的项目,并且一旦消费者使用了每个项目就可以进行垃圾回收?非常感谢您的帮助.

编辑:根据要求,添加了一个简单的演示代码:

// Entity is what we are going to process.// The finalizer will tell us when Entity is going to be garbage collected.class Entity{    private static int counter_;    private int ID_;    public int ID { get{ return ID_; } }    public Entity() { ID_ = counter++; }    ~Entity() { Console.Writeline("Destroying entity {0}.",ID_); }}...private BlockingCollection<Entity> jobQueue_ = new BlockingCollection<Entity>();private List<Task> tasks_ = new List<Task>();// This is the method to launch and wait for the tasks to finish the work.voID Run(){    tasks_.Add(Task.Factory.StartNew(ProduceEntity);    Console.Writeline("Start processing.");    tasks_.Add(Task.Factory.StartNew(ConsumeEntity);    Task.WaitAll(tasks_.ToArray());}// The producer creates Entity instances and add them to BlockingCollection.voID ProduceEntity(){    for(int i = 0; i < 10; i ++) // We are adding totally 10 entitIEs.    {        var newEntity = new Entity();        Console.Writeline("Create entity {0}.",newEntity.ID);        jobQueue_.Add(newEntity);    }    jobQueue_.CompleteAdding();}// The consumer takes entity,process it (and what I need: destroy it).voID ConsumeEntity(){    while(!jobQueue_.IsCompleted){        Entity entity;        if(jobQueue_.TryTake(entity))        {            Console.Writeline("Process entity {0}.",entity.ID);            entity = null;            // I would assume after GC,the entity will be finalized and garbage collected,but NOT.            GC.Collect();            GC.WaitForPendingFinalizers();            GC.Collect();        }    }    Console.Writeline("Finish processing.");}

输出是所有创建和处理消息,然后是“完成处理”.然后是来自实体的所有销毁消息.并且创建实体消息显示从0到9的Entity.ID以及显示从9到0的Entity.ID的销毁消息.

编辑:

即使我设置了BlockingCollection的绑定容量,所有进入它的项目只有在循环退出时才会终止,这很奇怪.

解决方法 ConcurrentQueue包含具有32个项目的内部数组的段.在段被垃圾收集之前,实体项不会被垃圾收集.从队列中取出所有32个项目后会发生这种情况.如果您更改示例以添加32个项目,您将在“完成处理”之前看到“销毁实体”消息. 总结

以上是内存溢出为你收集整理的c# – 任务并行库中的BlockingCollection不会自动释放基础实例的引用全部内容,希望文章能够帮你解决c# – 任务并行库中的BlockingCollection不会自动释放基础实例的引用所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1250223.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-07
下一篇 2022-06-07

发表评论

登录后才能评论

评论列表(0条)

保存