使用(池化)c#后清除对象变量



我正在研究一种池化算法,该算法接受一个已分配的对象,并将其回收以备以后分配。然而,例如,回收对象的问题之一是:

someObject obj = pool.alloc(); //gives me a new object if no previous allocations, If an allocation has been recycled, returns a previous allocation
obj.someVariable = "foo";
pool.recycle(obj);

上面的代码将采用现有的分配并保存它,这样我就不必分配任何额外的ram,以防我有另一个someObject。但是,以下情况会产生问题:

someObject obj = pool.alloc(); //gives me the above allocation
obj.otherVariable = "bar";
obj.dump();

因此,我将得到以下结果:

someVariable = foo
otherVariable = bar

上述方法产生了一个问题。如果出于某种原因(或其他人)有一个算法不在对象内部使用某些变量,那么旧值可能会导致不必要的行为。我试了一下,看看是否有办法再次调用默认构造函数(坏主意),而C#(谢天谢地)似乎不允许你这么做。然而,我想知道是否有办法使用反射来做到这一点?此外,清除对象中的变量是否会破坏避免malloc(new)的目的?换句话说,如果我把时间花在清除变量上,性能增益会变得最小吗?我正在努力自学拼箱,所以任何批评和建议都将不胜感激!

以下是查看池的一种方法:

只有当您重用一些复杂的设置工作时,池才是真正必要的,而这些工作可以通过检索已经存在的对象来避免。例如,对象池最著名的应用程序之一是"数据库连接"。

池对数据库连接(DBConn)有效,因为1)DBConn可以通过连接字符串来简单地识别;以及2)DBConn需要大量的工作和时间来建立。琐碎的识别是通过匹配连接字符串来完成的——如果两个连接字符串相同,那么它们建立的连接也应该相同。此外,一旦有了连接字符串,查找服务器地址、打开套接字、进行身份验证和建立连接可能需要数百毫秒的时间。这意味着池对数据库连接很有效,因为当一个连接被释放时,它可以在下次为同一个连接字符串请求连接时被重用。

.NET运行时环境非常擅长快速分配对象并释放它们,这样就不会出现内存问题。如果你担心的只是内存使用或分配速度,不要担心;您无法通过自己清空内存来击败编译器的性能。但是,如果您的对象有一些复杂、漫长的设置,可以通过从池中检索现有对象来避免,那么您可以找到一些好处。

池化的另一个好例子是视频游戏中的粒子系统。你有数百个粒子必须被创建,经历一个生命周期,然后被销毁,只有在旧粒子死亡后才能创建新粒子。一个典型的粒子系统将创建X个对象作为数组,并具有一个Reset()函数,该函数将死对象作为原始位置中新创建的粒子返回。这样做的原因再次是因为粒子可以被琐碎地识别,并且设置工作(为图形系统提供纹理、放置位置等)。

您的应用程序是否同时具有"琐碎的匹配识别"功能和可以避免的漫长设置过程?如果没有,每次只分配新的对象——我敢打赌你不会看到任何性能下降。

编辑:从性能的角度来看,让我们看看这里:

重置变量=O(N)赋值语句;使用反射可以显著提高

实例化一个新对象=一个malloc调用,一个构造函数调用;复杂程度取决于构造函数代码和内存碎片。

使用反射来重置变量是可行的,但您必须提前知道赋值的O(N)比malloc和构造函数更快。对于数据库连接,我知道条件是满足的;但你的游泳池是这样的吗?

编辑:从您下面的评论中,您可能确实发现了一种适合池化的情况。如果是这样的话,我建议理想的方法是为正在池化的任何类创建一个Reset()函数。尝试创建一个定义函数Reset()IPoolable接口。然后,对于您池中的每个类,定义Reset()函数,使其将所有关键变量清零。因为它是编译的,所以不会产生反射开销,并且可以维护动态代码无法实现的特定于对象的优化。

对于池,将池类定义为MyPool<IPoolable>;然后,无论何时检索到以前回收的对象,都可以在将其交还给调用者之前对其调用Reset()

最新更新