.Net Core EFCore多线程生命周期管理

1、多线程下EFCore的DbContext实例处理

       DbContext生命周期默认注入是Scope,每一次请求时创建一个实例,在当前请求的上下文中共用,当请求结束后,释放生命周期,释放数据库链接。若开启多线程,在不同的线程中使用同一个DbContext上下文,则报错如下:System.InvalidOperationException: A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.代码演示如下:.

 .Net Core EFCore多线程生命周期管理

解决办法: 在GetAsync中重新创建DbContext(new SecondHandDbContext),不使用请求注入的DbContext:

.Net Core EFCore多线程生命周期管理

2、多线程下生命周期已被释放

      生命周期为Scope方式,随着请求的结束,实例生命周期也会被释放,因此在多线程下若共享实例,容易出现实例已释放的错误,报错如下:Instances cannot be resolved and nested lifetimes cannot be created from this LifetimeScope as it (or one of its parent scopes) has already been disposed.Autofac   at Autofac.Core.Lifetime.LifetimeScope.BeginLifetimeScope(Object tag)。通过注入IServiceProvider,

解决办法:

1、在构造函数注入IServiceProvider,应用中通过IServiceProvider的GetService方法获取实例,最终发现IServiceProvider也已被释放,IServiceProvider只是当前请求的实例,该方法失败。

2、从当前应用中获取实例,构造函数注入IHost,通过host获取IServiceProvider:

.Net Core EFCore多线程生命周期管理 

在线程中通过_sp创建新的生命周期:

            using (var sp = _sp.CreateScope())

                      {

                          await Task.Delay(5000);

                          var applyReposity = sp.ServiceProvider.GetRequiredService<IApplyReposity>();

                          Console.WriteLine($"taskCode:{applyReposity.GetHashCode()},taskThreaId:{Thread.CurrentThread.ManagedThreadId}");

                          var model = await applyReposity.GetAsync(c => 1 == 1);

                          sp.Dispose();

                      }

.Net Core EFCore多线程生命周期管理

 .Net Core EFCore多线程生命周期管理

观察curThreaId与taskThreaId,Task.Run开启了新的线程,与当前主线程线程ID不同,当前请求中注入的IApplyReposity的实例_applyReposity编码是57588670,新线程中开启的新生命周期sp.ServiceProvider中获取的实例编码是2837748;主线程与子线程实例不再相关,解决主线程已释放,子线程获取不到实例的问题。