- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我们正在使用内存数据库 Exasol
,它确实提供了 Ado.Net 提供程序,但它似乎缺少一些重要的功能,如 ConnectionPooling
,因此每个连接根据请求创建和销毁,这会影响我们的性能,因为我们正在连接到 AWS
上的托管数据库。我已经创建了一个简单的 ConnectionPool
,具有Resize
的能力,请建议这是否可以达到目的,或者我需要做更多的事情。
请注意,我不是在寻找代码审查,而是对我在当前实现中可能遗漏的内容进行批判性分析,如果有可用的实现(Nuget、Git),我也可以重复使用。目前我正在根据大小调整大小,如何根据时间实现相同的大小,在一定的空闲持续时间内,应从队列中清除少量资源,从而减小大小。
重要细节:
ConcurrentQueue
从多个客户端安全地访问资源AutoResetEvent
进行等待,如果池为空则发出信号使用 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 实现这么小,而且对您的情况来说并不过分复杂。我只想添加少量建议,您可以自行研究。
StartNew
is Dangerous Stephen Cleary 的文章是一篇关于您用于调整逻辑大小的方法的好文章。最重要的部分是:
Thread "A" will run on whatever
TaskScheduler
is currently executing!
因此您的代码有时 可能会使用UI
线程上下文并降低应用程序的性能。如果它适合您(例如,对于 ASP.NET 应用程序),那很好,但如果不适合,我建议您使用 Task.Run
方法代替。您还可以查看 Stephen 关于 TPL
最佳实践的博客。
一般来说,调整大小的逻辑是通过一种简单的方式完成的,将大小加倍,因此如果您达到了限制,大小就会变成原来的两倍,反之亦然。我认为为用户提供管理此常量的能力可能会导致一些奇怪的错误,例如负池大小等。
所以你应该将你的属性 setter 设置为 private
并且,对于我来说,删除与调整大小有关的属性。也许将来您可以为您的应用程序平均收集池大小的统计信息,并将该参数用作默认值。
关于c# - Exasol Ado.Net 提供商的自定义连接池,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39392816/
我在前几天的测验中遇到了以下问题。 Consider the code fragment (assumed to be in a program in which all variables are
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 9 年前。 Improve this qu
我刚开始接触 Objective-C,一般来说是 C,所以我想这也是一个 C 问题。它更像是一个为什么的问题,而不是一个如何做的问题问题。 我注意到,在除以两个整数时,小数部分向下舍入为 0,即使结果
我是一名优秀的程序员,十分优秀!