gpt4 book ai didi

c# - Exasol Ado.Net 提供商的自定义连接池

转载 作者:太空宇宙 更新时间:2023-11-03 12:40:05 26 4
gpt4 key购买 nike

我们正在使用内存数据库 Exasol,它确实提供了 Ado.Net 提供程序,但它似乎缺少一些重要的功能,如 ConnectionPooling,因此每个连接根据请求创建和销毁,这会影响我们的性能,因为我们正在连接到 AWS 上的托管数据库。我已经创建了一个简单的 ConnectionPool,具有Resize 的能力,请建议这是否可以达到目的,或者我需要做更多的事情。

请注意,我不是在寻找代码审查,而是对我在当前实现中可能遗漏的内容进行批判性分析,如果有可用的实现(Nuget、Git),我也可以重复使用。目前我正在根据大小调整大小,如何根据时间实现相同的大小,在一定的空闲持续时间内,应从队列中清除少量资源,从而减小大小。

重要细节:

  1. 在内部使用 ConcurrentQueue 从多个客户端安全地访问资源
  2. 使用 AutoResetEvent 进行等待,如果池为空则发出信号
  3. 使用 TPL 调整操作的大小,而不停止调用代码,我的理解是即使客户端调用返回时也能正常工作,因为它在 Threadpool 线程

    class ExasolConnectionPool
    {
    /// <summary>
    /// Thread safe queue for storing the connection objects
    /// </summary>
    private ConcurrentQueue<EXAConnection> ExasolConnectionQueue { get; set; }

    /// <summary>
    /// Number of connections on the Connection pool
    /// </summary>
    private int _connectionCount;

    /// <summary>
    /// Max Pool Size
    /// </summary>
    private int MaxPoolSize { get; set; }

    /// <summary>
    /// Min Pool Size
    /// </summary>
    private int MinPoolSize { get; set; }

    /// <summary>
    /// Increase in Pool Size
    /// </summary>
    private int IncreasePoolSize { get; set; }

    /// <summary>
    /// Decrease in Pool Size
    /// </summary>
    private int DecreasePoolSize { get; set; }

    /// <summary>
    /// Connection string for the Connection pool connections
    /// </summary>
    private string ConnectionString { get; set; }

    /// <summary>
    /// Auto Reset event for the connection pool
    /// </summary>
    private AutoResetEvent ExasolConnectionPoolAre { get; set; }

    /// <summary>
    /// Connection pool specific Lock object
    /// </summary>
    private readonly object lockObject;

    /// <summary>
    /// Connection pool constructor
    /// </summary>
    /// <param name="connectionString"></param>
    /// <param name="poolSize"></param>
    public ExasolConnectionPool(string connectionString, int poolSize = 10)
    {
    // Set the Connection String
    ConnectionString = connectionString;

    // Intialize the Connection Queue
    ExasolConnectionQueue = new ConcurrentQueue<EXAConnection>();

    // Enqueue initial set of connections
    for (int counter = 0; counter < poolSize; counter++)
    {
    var exaConnection = new EXAConnection {ConnectionString = ConnectionString};

    ExasolConnectionQueue.Enqueue(exaConnection);
    }

    // Initialize Lock object
    lockObject = new object();

    // Set the Connection queue count
    _connectionCount = poolSize;

    // Max pool size
    MaxPoolSize = poolSize;

    // Min Pool Size
    MinPoolSize = 2;

    IncreasePoolSize = 5;

    DecreasePoolSize = 3;

    ExasolConnectionPoolAre = new AutoResetEvent(false);
    }

    /// <summary>
    ///
    /// </summary>
    /// <returns></returns>
    public EXAConnection GetConnection()
    {
    // Return ExaConnection object
    EXAConnection returnConnection;

    // Try Dequeue the connection object from the Concurrent Queue
    var validExasolConnection = ExasolConnectionQueue.TryDequeue(out returnConnection);

    // If No Valid connection is available, then wait using AutoReset signaling mechanism
    while (!validExasolConnection)
    {
    ExasolConnectionPoolAre.WaitOne();

    validExasolConnection = ExasolConnectionQueue.TryDequeue(out returnConnection);
    }

    // Thread safe connection count update
    Interlocked.Decrement(ref _connectionCount);

    Task.Factory.StartNew(() =>
    {
    lock (lockObject)
    {
    if (_connectionCount > MinPoolSize) return;

    for (var counter = 0; counter < IncreasePoolSize; counter++)
    {
    var exaConnection = new EXAConnection {ConnectionString = ConnectionString};

    ExasolConnectionQueue.Enqueue(exaConnection);

    Interlocked.Increment(ref _connectionCount);
    }
    }
    });

    return (returnConnection);
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="returnedConnection"></param>
    public void ReturnConnection(EXAConnection returnedConnection)
    {
    ExasolConnectionQueue.Enqueue(returnedConnection);

    Interlocked.Increment(ref _connectionCount);

    ExasolConnectionPoolAre.Set();

    Task.Factory.StartNew(() =>
    {
    lock (lockObject)
    {
    if (_connectionCount < MaxPoolSize * 1.5) return;

    for (var counter = 0; counter < DecreasePoolSize; counter++)
    {
    EXAConnection exaConnection;

    if (ExasolConnectionQueue.TryDequeue(out exaConnection))
    {
    exaConnection.Dispose();

    exaConnection = null;

    Interlocked.Decrement(ref _connectionCount);
    }
    }
    }
    });
    }
    }

最佳答案

您的池的实现很好。我不知道有任何 NuGet 实现这么小,而且对您的情况来说并不过分复杂。我只想添加少量建议,您可以自行研究。

  1. StartNew is Dangerous Stephen Cleary 的文章是一篇关于您用于调整逻辑大小的方法的好文章。最重要的部分是:

    Thread "A" will run on whatever TaskScheduler is currently executing!

    因此您的代码有时 可能会使用UI 线程上下文并降低应用程序的性能。如果它适合您(例如,对于 ASP.NET 应用程序),那很好,但如果不适合,我建议您使用 Task.Run方法代替。您还可以查看 Stephen 关于 TPL 最佳实践的博客。

  2. 一般来说,调整大小的逻辑是通过一种简单的方式完成的,将大小加倍,因此如果您达到了限制,大小就会变成原来的两倍,反之亦然。我认为为用户提供管理此常量的能力可能会导致一些奇怪的错误,例如负池大小等。

    所以你应该将你的属性 setter 设置为 private 并且,对于我来说,删除与调整大小有关的属性。也许将来您可以为您的应用程序平均收集池大小的统计信息,并将该参数用作默认值。

关于c# - Exasol Ado.Net 提供商的自定义连接池,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39392816/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com