MMO基础服务器架构(四):线程安全的对象池

更多代码细节,球球各位观众老爷给鄙人的开源项目点个Star,持续更新中~ 项目开源地址

4.线程安全的对象池类(采用线程安全的单例模式) 压测过~

需要实现对象池的对象都要继承IPool接口

namespace Common.Summer.core;

public interface IPool
{
    void ReturnPool(); //放回对象池,释放持有的引用
}
using System.Collections.Concurrent;
using Serilog;

namespace Common.Summer;

/// 
///     泛型对象池管理器
///     服务端对象池,线程安全
/// 
public class ObjPoolLockManager : BaseManager<ObjPoolLockManager>
{
    private readonly ConcurrentDictionary<string, PoolNode> pool = new();
    private static readonly object _poolLock = new();
    public int test;

    /// 
    ///     缓存池节点
    /// 
    private class PoolNode
    {
        public readonly List<object> poolList;
        private static readonly object lockObj = new(); // 用于保护LinkedList的访问

        public PoolNode()
        {
            poolList = new List<object>();
        }

        public void Push(object obj)
        {
            lock (lockObj) poolList.Add(obj);
        }

        public object PopTop()
        {
            object obj = null;
            lock (lockObj)
            {
                if (poolList.Count <= 0) return obj;
                obj = poolList[^1]; 
                poolList.RemoveAt(poolList.Count - 1);
            }
            return obj;
        }

        public int Count => poolList.Count;
    }

    /// 
    ///     从对象池获取对象
    ///
    public async ValueTask<T> PopAsync<T>(Func<Task<T>> objectFactory = null, Action<T> callback = null)
        where T : class
    {
        T? obj;
        if (pool.TryGetValue(typeof(T).FullName, out var poolNode) && poolNode.Count > 0)
            obj = poolNode.PopTop() as T;
        else
            obj = await objectFactory();
        lock (_poolLock)
        {
            callback?.Invoke(obj);
            return obj;
        }
    }

    public T? Pop<T>(Func<T> objectFactory, Action<T> callback = null)
    {
        lock (_poolLock)
        {
            T? obj;
            if (pool.TryGetValue(typeof(T).FullName, out var poolNode) && poolNode.Count > 0)
            {
                Interlocked.Add(ref test, 1);
                obj = (T)poolNode.PopTop();
            }
            else
                obj = objectFactory();
            callback?.Invoke(obj);
            return obj;
        }
    }

    /// 
    ///     将对象归还到池中
    /// 
    public void Push<T>(T obj)
    {
        var poolNode = pool.GetOrAdd(typeof(T).FullName, _ => new PoolNode());
        poolNode.Push(obj);
    }

    /// 
    ///     预加载对象池
    /// 
    public async ValueTask PreloadAsync<T>(int count, Func<Task<T>> objectFactory)
    {
        var poolNode = pool.GetOrAdd(typeof(T).FullName, _ => new PoolNode());

        // 异步预加载指定数量的对象
        for (var i = 0; i < count; i++)
        {
            var obj = await objectFactory();
            poolNode.Push(obj);
        }
    }

    /// 
    ///     清空对象池
    /// 
    public void Clear()
    {
        foreach (var type in pool.Keys)
            RemoveType(type);
        pool.Clear();
    }

    /// 
    ///     移除指定类型的对象池
    /// 
    public void RemoveType(string type)
    {
        if (!pool.TryGetValue(type, out var poolNode)) return;
        poolNode.poolList.Clear();
        pool.TryRemove(type, out _);
    }
}

扩展方法

namespace Common.Summer.core;

public static class MoonExtension
{
    public static T MoonObjGetPool<T>(this object obj, Func<T> _fun, Action<T> callback = null) where T : class
    {
        return ObjPoolLockManager.Instance.Pop( _fun, callback);
    }
    
    public static void MoonObjPushPool<T>(this T obj) //提供便利的对象池放入语法
    {
        ObjPoolLockManager.Instance.Push(obj);
        //如:this.MoonObjPushPool();
    }
}

压测报告

=== 压测报告 ===
运行时间: 30.05s
计划任务总数: 7377
实际执行次数: 69689
QPS: 2319/s(只测试了单一线程的Task处理)
- 对象池使用次数: 7324
using System.Diagnostics;
using Common.Summer;
using Org.BouncyCastle.Utilities.Zlib;
using Serilog;

namespace TestClient;

public class SchedulerStressTest
{
    private const int ThreadCount = 4;     // 并发线程数
    private const int TasksPerSecond = 1000; // 每秒任务数
    private const int TestDurationSec = 30; // 测试持续时间

    public static async Task RunTest()
    {
        //初始化日志环境
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()	// debug, info, warn, error 优先级
            .WriteTo.Async(loggerSink =>loggerSink.Console())		//输出到控制台	
            .WriteTo.Async(loggerSink => loggerSink.File("logs\\test.txt", rollingInterval: RollingInterval.Day)) //输出到文件,多久生成
            .CreateLogger();
        
        var scheduler = new Scheduler();
        var cts = new CancellationTokenSource(TimeSpan.FromSeconds(TestDurationSec));
        
        // 测试指标
        var totalExecuted = 0L;
        var totalScheduled = 0L;
        var stopwatch = Stopwatch.StartNew();
        scheduler.Start();
        
        // 创建压测任务(持续生成)
        var producers = Enumerable.Range(0, ThreadCount).Select(_ => 
            Task.Run(async () =>
            {
                var rnd = new Random();
                while (!cts.IsCancellationRequested)
                {
                    var taskId = scheduler.AddTask(() => 
                    {
                        Thread.SpinWait(1000); // 1ms负载
                        Interlocked.Increment(ref totalExecuted);
                    }, 
                    TimeSpan.FromMilliseconds(10), 
                    repeatCount: 10);

                    Interlocked.Increment(ref totalScheduled);
                    Log.Debug("{0}  {1}", totalExecuted, totalScheduled);
                    
                    // 10%概率取消
                    if (rnd.Next(0, 10) == 0)
                    {
                        scheduler.CancelTask(taskId);
                    }

                    // 控制任务生成速率
                    if (totalScheduled >= TasksPerSecond * TestDurationSec) break;
                    try
                    {
                        await Task.Delay(1000 / (TasksPerSecond / ThreadCount), cts.Token);
                    }
                    catch (Exception e)
                    {
                        break;
                    }
                }
            }, cts.Token)
        ).ToArray();

        // 等待测试时间结束
        await Task.WhenAll(producers);
        scheduler.Stop(); // 确保调度器停止

        // 输出测试报告
        stopwatch.Stop();
        Console.WriteLine($"=== 压测报告 ===");
        Console.WriteLine($"运行时间: {stopwatch.Elapsed.TotalSeconds:F2}s");
        Console.WriteLine($"计划任务总数: {totalScheduled}");
        Console.WriteLine($"实际执行次数: {totalExecuted}");
        Console.WriteLine($"QPS: {totalExecuted / stopwatch.Elapsed.TotalSeconds:F0}/s");
        //Console.WriteLine($"  - 对象池使用次数: {ObjPoolLockManager.Instance.test}");
    }
}

//
public static class Program 
{
    public static async Task Main()
    {
        await SchedulerStressTest.RunTest();
        Console.ReadKey(); // 防止控制台立即关闭
    }
}

你可能感兴趣的:(MMO双端游戏架构,c#,游戏,服务器)