在EF Core 6中是如何对DbContextPool进行改进

  起因

  前几天通过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等.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值