【问题标题】:C# byte [ ] operations - shall I use ArrayPool or MemoryPool?C# byte [] 操作 - 我应该使用 ArrayPool 还是 MemoryPool?
【发布时间】:2021-11-24 14:11:24
【问题描述】:

我正在编写一个服务器应用程序。它接受数以千计的传入 socket 连接,每个连接都发送和接收消息。

每次通过socket接收或发送消息时,我习惯分配新的byte[]缓冲区,那么它们就是垃圾收集:

byte[] receivingBuffer = new byte[bufferSize];

为了提高性能,我想重用 byte[] 缓冲区。我应该使用 ArrayPool 还是 MemoryPool

或者我应该创建一个 ObjectPool 的固定长度字节 [] 缓冲区?例如,如果我发送和接收的消息从未超过 100 KB,那么我创建一个 100 KB 字节[] 缓冲区的 ObjectPool。每次我需要发送或接收消息时,我都会获得其中一个缓冲区。

【问题讨论】:

  • "每次通过套接字接收或发送消息时,我都需要分配新的 byte[] 缓冲区,然后它们被垃圾回收:" 不,你不需要 - 你搞错了你真正“需要”做什么。
  • 你是对的——我“曾经”这样做过——我知道这是不对的——这就是为什么我想改用正确的方式。你会告诉我正确的方法吗?

标签: sockets memory-pool arraypools


【解决方案1】:

做了一些研究和测试。 ArrayPool 是正确的使用方法,它将显着提高性能。

class Program
{
    private static ManualResetEvent m_event = new ManualResetEvent(false);
    private static DateTime m_dtStart;
    private static int m_iNumOfIterations = 0;
    private static int m_iNumOfExceptions = 0;

    private static double m_dAvgSizeRatio = 0;
    private static object m_lock = new object();

    private static void ReportSizeRatio(double dRatio)
    {
        lock (m_lock)
        {
            m_dAvgSizeRatio = (m_dAvgSizeRatio * m_iNumOfIterations + dRatio) / (m_iNumOfIterations + 1);
            m_iNumOfIterations++;
        }
    }

    /// <summary>
    /// When using ArrayPool: 
    /// - CPU:    1 ~ 1.5%
    /// - Memory: 67 MB
    /// - Speed:  9130 runs/sec
    /// - Given buffer is 1.56 times bigger than asked for.
    /// 
    /// When NOT using ArrayPool: 
    /// - CPU:    20 ~ 25%
    /// - Memory: 500 ~ 1000 MB
    /// - Speed:  5300 runs/sec
    /// 
    /// Conclusion: huge improvement in performance.
    /// </summary>
    /// <param name="obj"></param>
    private static void Test(object obj)
    {
        TrueRandom random = new TrueRandom(500, 800);
        m_event.WaitOne();

        while (true)
        {
            int iDesiredSize = random.GetRandomInteger() * 1000;
            byte[] buffer = null;

            try
            {
                //buffer = ArrayPool<byte>.Shared.Rent(iDesiredSize);
                buffer = new byte[iDesiredSize];

                ReportSizeRatio((double)buffer.Length / (double)iDesiredSize);
            }
            catch
            {
                Interlocked.Increment(ref m_iNumOfExceptions);
            }

            Thread.Sleep(100);
            //ArrayPool<byte>.Shared.Return(buffer);
        }
    }


    static void Main(string[] args)
    {

        for (int i = 0; i < 1000; i++)
        {
            Thread thread = new Thread(Test);
            thread.Start();
        }

        Console.WriteLine("All threads fired.");
        m_dtStart = DateTime.Now;
        m_event.Set();

        while (true)
        {
            Thread.Sleep(1000);
            Console.Clear();
            Console.WriteLine($"Iterations/sec: { (int)(m_iNumOfIterations / (DateTime.Now - m_dtStart).TotalSeconds) }, Ave rented size: { (m_dAvgSizeRatio * 100d).ToString("0.0") }%, exceptions: { m_iNumOfExceptions }.");
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-15
    • 1970-01-01
    • 1970-01-01
    • 2010-10-25
    • 2014-01-05
    • 1970-01-01
    • 1970-01-01
    • 2018-09-05
    相关资源
    最近更新 更多