如何避免对象分配?如何重用对象而不是分配对象

本文关键字:对象 分配 何避免 何重用 | 更新日期: 2023-09-27 18:14:10

我的财务软件不断处理几乎相同的对象。例如,我在网上有这样的数据:

HP 100 1
HP 100 2
HP 100.1 1
etc.

我每秒大约有1000条更新。

每个更新都存储在object中,但我不想在运行中分配这些对象以提高延迟。我只在短时间内使用物品——我接受它们,应用它们,免费使用它们。对象一旦被释放,它实际上可以被用于另一个数据包。

所以我需要一些存储(可能是环缓冲区),它一次分配所需数量的对象,并允许"获取"answers"释放"它们。在c#中做到这一点的最好方法是什么?

每个对象都有id,我依次分配id's并释放sequentially。例如,我收到id的1 23,然后我释放1, 2, 3。所以任何FIFO集合都可以工作,但我正在寻找一些涵盖所需功能的库类。

。我需要FIFO收集,不分配对象,但重用它们,并允许重新配置它们。

乌利希期刊指南

我已经添加了我想要的实现。这是未经测试的代码,可能有bug。想法很简单。写入器应该调用Obtain Commit方法。阅读器应该调用TryGet方法。读写器可以从不同的线程访问这个结构体:

public sealed class ArrayPool<T> where T : class
{
    readonly T[] array;
    private readonly uint MASK;
    private volatile uint curWriteNum;
    private volatile uint curReadNum;
    public ArrayPool(uint length = 1024) // length must be power of 2
    {
        if (length <= 0) throw new ArgumentOutOfRangeException("length");
        array = new T[length];
        MASK = length - 1;
    }
    /// <summary>
    /// TryGet() itself is not thread safe and should be called from one thread.
    /// However TryGet() and Obtain/Commit can be called from different threads
    /// </summary>
    /// <returns></returns>
    public T TryGet()
    {
        if (curReadNum == curWriteNum)
        {
            return null;
        }
        T result = array[curReadNum & MASK];
        curReadNum++;
        return result;
    }
    public T Obtain()
    {
        return array[curWriteNum & MASK];
    }
    public void Commit()
    {
        curWriteNum++;
    }
}

关于我的实现的评论是受欢迎的,也许一些库方法可以取代这个简单的类?

如何避免对象分配?如何重用对象而不是分配对象

我不认为你应该跳过这个问题,根据我对这个问题的评论-然而,一个简单的方法将是这样的:

public sealed class MicroPool<T> where T : class
{
    readonly T[] array;
    public MicroPool(int length = 10)
    {
        if (length <= 0) throw new ArgumentOutOfRangeException("length");
        array = new T[length];
    }
    public T TryGet()
    {
        T item;
        for (int i = 0; i < array.Length; i++)
        {
            if ((item = Interlocked.Exchange(ref array[i], null)) != null)
                return item;
        }
        return null;
    }
    public void Recycle(T item)
    {
        if(item == null) return;
        for (int i = 0; i < array.Length; i++)
        {
            if (Interlocked.CompareExchange(ref array[i], item, null) == null)
                return;
        }
        using (item as IDisposable) { } // cleaup if needed
    }
}

如果负载是突发的,您可以使用GC的延迟模式通过延迟收集来抵消开销。这不是灵丹妙药,但在某些情况下它会非常有用。

我不确定,如果这是您需要的,但您总是可以创建一个将要使用的对象池。初始化对象类型的List。然后,当您需要使用某个对象时,将其从列表中删除,并在使用完成后将其添加回去。

http://www.codeproject.com/Articles/20848/C-Object-Pooling是个好的开始。

希望我能帮到你,哪怕是一点点。

如果您只是担心GC运行所花费的时间,那么不必担心-它无法被您自己所做的任何事情所击败。

然而,如果你的对象的构造函数做了一些工作,那么可能会更快地缓存它们。一个相当直接的方法是使用ConcurrentBag

本质上,你所做的就是使用ConcurrentBag.Add()预先填充一组对象(如果你想的话——或者你可以从空开始,让它增长)。

然后当你需要一个新对象时,你使用ConcurrentBag.TryTake()抓取一个对象。

如果TryTake()失败,则只需创建一个新对象并使用它。

无论你是从袋子里抓取一个对象还是创建一个新对象,一旦你完成了它,你只需使用ConcurrentBag.Add()

将对象放回袋子里

一般来说,你的包会达到一定的尺寸,但不会更大(但你可能想要仪器检查东西)。

无论如何,我总是会做一些计时,看看像这样的更改是否真的有任何不同。除非对象构造函数做了相当多的工作,否则很可能不会有太大的区别。