• Lock Free ObjectPool<T>的C#实现 (对象池)


    最近实现了一个LockFree的对象池

    主要的想法是:

      1.复用构造出来的对象
      2.避免重复创建和销毁对象对GC造成的压力

      3.避免重复创建对象造成的资源消耗

    最适合的场景是:

      1.构造对象很慢,并且需要构造很多个对象的情况

    主要技术特征:

      1. C#4.0的实现(可以降级到2.0)

      2. 内部没有使用普通的lock,而是使用Lock Free的实现方式

      3. 将常用的取回对象的方式,换成委托运行, 这样的话ObjectPool可以帮你自动将对象压回队列

      4. ObjectPool支持对象池上下限的设置(如果移除该功能性能还会提高很多!)

    以下是实现代码:

        /// <summary>
    /// 对象池 (有上下限的版本..如果不要控制上限的话性还能好很多)
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public sealed class ObjectPool<T>
    {
    #region private Fields 为了调试方便 吧一些变量弄成了Public, 实际使用中请关掉
    private int isTaked = 0;
    private Queue<T> queue = new Queue<T>();
    private Func<T> func = null;
    private int currentResource = 0;
    public int tryNewObject = 0;
    private int minSize = 0;
    private int maxSize = 0;
    #endregion

    #region private methods
    private void Enter()
    {
    while (Interlocked.Exchange(ref isTaked, 1) != 0)
    {
    }
    }
    private void Leave()
    {
    Thread.VolatileWrite(ref isTaked, 0);
    }
    #endregion

    /// <summary>
    /// 构造一个对象池
    /// </summary>
    /// <param name="func">用来初始化对象的函数</param>
    /// <param name="minSize">对象池下限</param>
    /// <param name="maxSize">对象池上限</param>
    public ObjectPool(Func<T> func, int minSize = 1, int maxSize = 5)
    {
    if (func == null)
    {
    throw new ArgumentNullException("func");
    }
    if (minSize < 0)
    {
    throw new ArgumentOutOfRangeException("minSize");
    }
    if (maxSize < 0)
    {
    throw new ArgumentOutOfRangeException("maxSize");
    }
    if (maxSize < minSize)
    {
    throw new ArgumentException("maxSize can not be less than minSize");
    }

    this.minSize = minSize;
    this.maxSize = maxSize;
    for (int i = 0; i < minSize; i++)
    {
    this.queue.Enqueue(func());
    }

    this.currentResource = minSize;
    this.tryNewObject = minSize;
    this.func = func;
    }

    /// <summary>
    /// 从对象池中取一个对象出来,并执行, 执行完成以后会自动将对象放回池中
    /// </summary>
    /// <param name="action">一个可用的对象</param>
    public void Run(Action<T> action)
    {
    if (action == null)
    {
    throw new ArgumentNullException("func");
    }
    T t = default(T);
    try
    {
    Start:
    if (Interlocked.Decrement(ref this.currentResource) < 0)
    {
    if (this.tryNewObject < this.maxSize)
    {
    Interlocked.Increment(ref this.tryNewObject);
    t = func();
    Interlocked.Increment(ref this.currentResource);
    }
    else
    {
    Interlocked.Increment(ref this.currentResource);
    goto Start;
    }
    }
    else
    {
    this.Enter();
    t = this.queue.Dequeue();
    this.Leave();
    }

    action(t);
    }
    finally
    {
    this.Enter();
    this.queue.Enqueue(t);
    this.Leave();
    Interlocked.Increment(ref currentResource);
    }
    }

    /// <summary>
    /// 看看现在的Queue中有多少个资源,线程不安全...
    /// </summary>
    [Obsolete]
    public int ResourceCountInQueue { get { return queue.Count(); } }
    }



    测试代码如下:(注意测试代码是4.0的)

           static void Main(string[] args)
    {
    //测试代码
    int length = 1 * 1000 * 1000;
    Stopwatch sw = Stopwatch.StartNew();
    ObjectPool<MD5> pool = new ObjectPool<MD5>(() =>
    {
    Thread.Sleep(1000);//模拟缓慢的构造情况
    return new MD5CryptoServiceProvider();
    });

    Parallel.For(0, length, p =>
    {
    pool.Run(md5 =>
    {
    md5.ComputeHash(Guid.NewGuid().ToByteArray());//模拟一个运算场景
    });
    });
    sw.Stop();
    Console.WriteLine(sw.ElapsedMilliseconds);
    Console.WriteLine(length);
    Console.WriteLine(pool.ResourceCountInQueue);
    }

    顺便测试一下机器性能...这个代码在我机器上大约要跑10秒钟......- -#

    欢迎大家指正~

  • 相关阅读:
    Golanggin框架入门教程
    Golang模板引擎快速入门教程
    eltable 根据后台返回数据动态显示列
    ThinkPHP网站安全方案
    织梦(DedeCMS)安全方案
    帝国CMS安全方案
    STC89C52驱动MAX7219LED点阵级联, 文字滚动效果
    二十二、插槽(slot)
    十九、父子组件的通信(父组件向子组件传递数据)
    二十六、Webpack安装
  • 原文地址:https://www.cnblogs.com/PurpleTide/p/2402254.html
Copyright © 2020-2023  润新知