有没有人有足够的资源来实现共享资源池策略,以实现有限的SQL连接池资源?(即将完全实现它是线程安全的)。
为了进一步澄清@Aaronaught请求,池使用将用于平衡对外部服务的请求。相比于我的直接观点,将其置于一种可能更容易立即理解的场景中。我有一个会话对象,其功能ISession与NHibernate中的对象类似。每个唯一的会话都管理着它与数据库的连接。当前,我有1个长时间运行的会话对象,并且遇到问题,服务提供商在此限制我对单个会话的使用。
ISession
由于他们不希望将单个会话视为长期运行的服务帐户,因此他们显然将其视为锤打服务的客户。这使我想到这里的问题,而不是创建一个单独的会话,而不是创建一个不同的会话池,并将请求拆分到多个会话中的服务中,而不是像我以前那样创建一个联络点。
希望背景可以提供一些价值,但是可以直接回答您的一些问题:
问: 创建对象是否昂贵? 答: 没有对象是有限的资源池
问: 它们会经常被获取/发布吗? 答: 是的,他们可以再次想到NHibernate ISessions,通常在每个单页请求期间获取并释放1。
问: 简单的先到先得就足够了吗?还是您需要更智能的东西,即可以防止饥饿? 答: 一个简单的循环类型分配就足够了,由于饥饿,我认为您的意思是,如果没有可用的会话,则呼叫者会被阻止等待释放。这实际上并不适用,因为会话可以由不同的呼叫者共享。我的目标是在多个会话中分配使用情况,而不是单个会话。
我认为这可能与对象池的正常使用有所不同,这就是为什么我最初将这一部分省略并计划只是为了适应模式以允许对象共享而不是让饥饿情况发生的原因。
问: 如何处理优先级,延迟加载与急切加载等问题? 答: 不涉及优先级,为简单起见,仅假设我将在创建池本身时创建可用对象池。
该DOTNET芯具有添加到该基类库(BCL)对象池的实施方案。您可以在此处阅读原始的GitHub问题,并查看System.Buffers的代码。当前,ArrayPool是唯一可用的类型,用于合并数组。有一个很好的博客文章在这里。
ArrayPool
namespace System.Buffers { public abstract class ArrayPool<T> { public static ArrayPool<T> Shared { get; internal set; } public static ArrayPool<T> Create(int maxBufferSize = <number>, int numberOfBuffers = <number>); public T[] Rent(int size); public T[] Enlarge(T[] buffer, int newSize, bool clearBuffer = false); public void Return(T[] buffer, bool clearBuffer = false); } }
在ASP.NET Core中可以看到其用法示例。因为它在dotnet核心BCL中,所以ASP.NET Core可以与其他对象(例如Newtonsoft.Json的JSON序列化器)共享它的对象池。您可以阅读此博客文章,以获得有关Newtonsoft.Json如何执行此操作的更多信息。
新的Microsoft Roslyn C#编译器包含ObjectPool类型,该类型用于合并经常使用的对象,这些对象通常会被更新并非常频繁地收集垃圾。这减少了必须执行的垃圾收集操作的数量和大小。有几个不同的子实现都使用ObjectPool(请参阅:为什么在Roslyn中有这么多的对象池实现?)。
1- SharedPools-存储20个对象的池,如果使用BigDefault,则存储100个对象。
// Example 1 - In a using statement, so the object gets freed at the end. using (PooledObject<Foo> pooledObject = SharedPools.Default<List<Foo>>().GetPooledObject()) { // Do something with pooledObject.Object } // Example 2 - No using statement so you need to be sure no exceptions are not thrown. List<Foo> list = SharedPools.Default<List<Foo>>().AllocateAndClear(); // Do something with list SharedPools.Default<List<Foo>>().Free(list); // Example 3 - I have also seen this variation of the above pattern, which ends up the same as Example 1, except Example 1 seems to create a new instance of the IDisposable [PooledObject<T>][4] object. This is probably the preferred option if you want fewer GC's. List<Foo> list = SharedPools.Default<List<Foo>>().AllocateAndClear(); try { // Do something with list } finally { SharedPools.Default<List<Foo>>().Free(list); }
2- ListPool和StringBuilderPool-不是严格分开实现,而是围绕上面显示的SharedPools实现进行包装,专门用于List和StringBuilder。因此,这将重用存储在SharedPools中的对象池。
// Example 1 - No using statement so you need to be sure no exceptions are thrown. StringBuilder stringBuilder= StringBuilderPool.Allocate(); // Do something with stringBuilder StringBuilderPool.Free(stringBuilder); // Example 2 - Safer version of Example 1. StringBuilder stringBuilder= StringBuilderPool.Allocate(); try { // Do something with stringBuilder } finally { StringBuilderPool.Free(stringBuilder); }
3- PooledDictionary和PooledHashSet-它们直接使用ObjectPool并具有完全独立的对象池。存储128个对象的池。
// Example 1 PooledHashSet<Foo> hashSet = PooledHashSet<Foo>.GetInstance() // Do something with hashSet. hashSet.Free(); // Example 2 - Safer version of Example 1. PooledHashSet<Foo> hashSet = PooledHashSet<Foo>.GetInstance() try { // Do something with hashSet. } finally { hashSet.Free(); }
该库提供MemoryStream对象池。它是的直接替代品System.IO.MemoryStream。它具有完全相同的语义。它是由Bing工程师设计的。在此处阅读博客文章,或在GitHub上查看代码。
MemoryStream
System.IO.MemoryStream
var sourceBuffer = new byte[]{0,1,2,3,4,5,6,7}; var manager = new RecyclableMemoryStreamManager(); using (var stream = manager.GetStream()) { stream.Write(sourceBuffer, 0, sourceBuffer.Length); }
注意,RecyclableMemoryStreamManager应该声明一次,它将在整个过程中都有效-这就是池。如果需要,可以使用多个池。
RecyclableMemoryStreamManager