起因
前几天通过GitHub看到EF Core 修改DbContextPool默认大小,由原来的128改为1024.便打开DbContextPool源码学习了一番.
EF Core 6中将DbContextPool的默认大小从128改为1024
DbContextPool源码学习
public class DbContextPool : IDbContextPool, IDisposable, IAsyncDisposable
where TContext : DbContext
{
//默认大小由原来的128,改为1024
public const int DefaultPoolSize=1024;
//队列
private readonly ConcurrentQueue _pool=new();
//缓存创建DbContext对象(或者集成DbContext对象的实例)委托
//该委托 相当于new DbContext(),性能比反射高很多
private readonly Func _activator;
private int _maxSize;
private int _count;
//
public DbContextPool(DbContextOptions options)
{
_maxSize=options.FindExtension()?.MaxPoolSize DefaultPoolSize;
if (_maxSize <=0)
{
throw new ArgumentOutOfRangeException(nameof(CoreOptionsExtension.MaxPoolSize), CoreStrings.InvalidPoolSize);
}
options.Freeze();
_activator=CreateActivator(options);
}
//1.获取DbContext对象或继承DbContext对象构造方法和参数
//2.通过表达式树创建并返回一个委托
private static Func CreateActivator(DbContextOptions options)
{
var constructors=typeof(TContext).GetTypeInfo().DeclaredConstructors.Where(c=> !c.IsStatic && c.IsPublic).ToArray();
if (constructors.Length==1)
{
var parameters=constructors[0].GetParameters();
if (parameters.Length==1
&& (parameters[0].ParameterType==typeof(DbContextOptions)
|| parameters[0].ParameterType==typeof(DbContextOptions)))
{
return Expression.Lambda>(Expression.New(constructors[0], Expression.Constant(options)))pile();
}
}
throw new InvalidOperationException(CoreStrings.PoolingContextCtorError(typeof(TContext).ShortDisplayName()));
}
//1. 如果DbContext池有DbContext对象,从队列中获取
//2. 如果队里中,没有DbContext,则由委托创建DbContext
public virtual IDbContextPoolable Rent()
{
if (_pool.TryDequeue(out var context))
{
Interlocked.Decrement(ref _count);
Check.DebugAssert(_count >=0, $"_count is {_count}");
return context;
}
context=_activator();
context.SnapshotConfiguration();
return context;
}
// 1.当DbContext对象使用完毕,队列中的DbContext数量没有超过默认值1024,则DbContext放入队列中
// 2.如果队列中超过1024这个默认值,则DbContext进行文凭释放
public virtual void Return(IDbContextPoolable context)
{
if (Interlocked.Increment(ref _count) <=_maxSize)
{
context.ResetState();
_pool.Enqueue(context);
}
else
{
PooledReturn(context);
}
}
// 归还DbContext的异步实现
public virtual async ValueTask ReturnAsync(IDbContextPoolable context, CancellationToken cancellationToken=default)
{
if (Interlocked.Increment(ref _count) <=_maxSize)
{
await context.ResetStateAsync(cancellationToken).ConfigureAwait(false);
_pool.Enqueue(context);
}
else
{
PooledReturn(context);
}
}
private void PooledReturn(IDbContextPoolable context)
{
Interlocked.Decrement(ref _count);
Check.DebugAssert(_maxSize==0 || _pool.Count <=_maxSize, $"_maxSize is {_maxSize}");
context.ClearLease();
context.Dispose();
}
public virtual void Dispose()
{
_maxSize=0;
while (_pool.TryDequeue(out var context))
{
context.ClearLease();
context.Dispose();
}
}
public virtual async ValueTask DisposeAsync()
{
_maxSize=0;
while (_pool.TryDequeue(out var context))
{
context.ClearLease();
await context.DisposeAsync().ConfigureAwait(false);
}
}
}
还是学到了不少东西,比如使用表达式树创建委托对象,在缓存委托对象,而不是通过反射的方式创建(性能不佳).还有就是使用原子操作判断队列的数量,是否达到最大值,使用ConncurentQueue队列而不是使用Queue等.