Allowing iteration without generating any garbage(允许迭代而不产生任何垃圾)
问题描述
我在实现 IEnumerable 接口的对象池中有以下代码.
I have the following code in an object pool that implements the IEnumerable interface.
public IEnumerable<T> ActiveNodes
{
get
{
for (int i = 0; i < _pool.Count; i++)
{
if (_pool[i].AvailableInPool)
{
yield return _pool[i];
}
}
}
}
据我所知(根据 this 问题),这将生成垃圾作为 IEnumerable需要收集对象._pool 中的任何元素都不会被收集,因为池的目的是保留对所有元素的引用以防止垃圾产生.
As far as I know (according to this question), this will generate garbage as the IEnumerable object will need to be collected. None of the elements in _pool will ever be collected, as the purpose of the pool is to keep references to all of them to prevent garbage creation.
任何人都可以提出一种方法来允许在 _pool 上进行迭代,以免产生垃圾吗?
Can anyone suggest a way to allow iteration over _pool so that no garbage is generated?
当迭代池时,池中所有具有 AvailableInPool == true 的项目都应该被迭代.顺序无关紧要.
When iterating over pool, all of the items in pool that have AvailableInPool == true should be iterated over. Order doesn't matter.
推荐答案
在任何正常"设计中迭代项目通常会导致创建一个新的可枚举对象.创建和处理对象的速度非常快,因此只有在非常特殊的情况下(低延迟是最优先考虑的)垃圾回收才会(我说可能")成为问题.
Iterating items will in any 'normal' design usually result in the creation of a new enumerable object. Creating and disposing objects is very fast, so only in very special scenarios (where low latency is the top most priority) garbage collections could (I say 'could') be a problem.
通过返回不实现IEnumerable的结构,可以实现没有垃圾的设计.C# 编译器仍然可以迭代此类对象,因为 foreach 语句使用鸭子类型.例如,.NET 的 List<T> 就采用了这种方法.
A design without garbage is possible by returning structures that don't implement IEnumerable. The C# compiler can still iterate such objects, because the foreach statement uses duck typing. .NET's List<T>, for instance, takes this approach.
当在数组和 List<T> 上使用 foreach 时,不会产生垃圾.在数组上使用 foreach 时,C# 会将操作转换为 for 语句,而 List<T> 已经实现了 struct 枚举器,导致 foreach 不产生垃圾.
When using foreach over both an array and List<T>, no garbage will be generated. When using foreach on an array, C# will transform the operation to a for statement, while List<T> already implements a struct enumerator, causing the foreach to produce no garbage.
这里是一个struct enumerable和struct enumerator.当您返回可枚举时,C# 编译器可以对其进行 foreach:
Here is a struct enumerable and struct enumerator. When you return the enumerable, the C# compiler can foreach over it:
public struct StructEnumerable<T>
{
private readonly List<T> pool;
public StructEnumerable(List<T> pool)
{
this.pool = pool;
}
public StructEnumerator<T> GetEnumerator()
{
return new StructEnumerator<T>(this.pool);
}
}
这里是StructEnumerator:
public struct StructEnumerator<T>
{
private readonly List<T> pool;
private int index;
public StructEnumerator(List<T> pool)
{
this.pool = pool;
this.index = 0;
}
public T Current
{
get
{
if (this.pool == null || this.index == 0)
throw new InvalidOperationException();
return this.pool[this.index - 1];
}
}
public bool MoveNext()
{
this.index++;
return this.pool != null && this.pool.Count >= this.index;
}
public void Reset()
{
this.index = 0;
}
}
您可以简单地返回 StructEnumerable<T>,如下所示:
You can simply return the StructEnumerable<T> as follows:
public StructEnumerable<T> Items
{
get { return new StructEnumerable<T>(this.pool); }
}
而 C# 可以使用普通的 foreach 对其进行迭代:
And C# can iterate over this with a normal foreach:
foreach (var item in pool.Items)
{
Console.WriteLine(item);
}
请注意,您不能使用 System.Linq.Enumerable 对项目进行 LINQ,为此您需要 IEnumerable<T> 接口,这涉及创建枚举器和,因此,垃圾收集.当然,您可以构建自己的 LINQ 扩展方法,但这不太可能有帮助,因为这通常仍会导致创建新对象(当为使用的委托生成闭包时).
Note that you can't LINQ over the item using System.Linq.Enumerable You need the IEnumerable<T> interface for that, and that involves creating enumerators and, therefore, garbage collection. You could, of course, build your own LINQ extension methods, but that will unlikely help, because that will often still result in new objects being created (when closures are being generated for used delegates).
这篇关于允许迭代而不产生任何垃圾的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:允许迭代而不产生任何垃圾
基础教程推荐
- 如果有人提交恶意软件Nuget包怎么办? 2022-01-01
- Moq It.Is<>不匹配 2022-01-01
- 如何使用 .Net 检查 Active Directory 服务器是否已启动并正在运行? 2022-01-01
- 禁止输入少量字符,例如'<'、'&a 2022-01-01
- .NET SerialPort DataReceived 事件未触发 2022-01-01
- C# 从 List<List<int>> 中删除重 2022-01-01
- Azure Functions:CosmosDBTrigger 未在 Visual Studio 中触发 2022-01-01
- 当值可以是对象或空数组时反序列化 JSON 2022-01-01
- WPF 模态进度窗口 2022-01-01
- 我应该在后面的代码中直接使用 Linq To SQL 还是使 2022-01-01
