多线程上下文切换 多线程下的调用上下文 : CallContext( 三 )

上面示例代码的运行结果如下图所示:

多线程上下文切换 多线程下的调用上下文 : CallContext

文章插图
根据上面的示例运行结果 , 我们又可以得到以下一些结论:
1、FreeNamedDataSlot只能清除当前线程的数据槽
2、LogicalSetData只会存储当前线程以及子线程的数据槽;
3、LogicalGetData获取的是当前线程或父线程的数据槽对象 , 拿到的是对象的引用 , 因此如果对其进行修改 , 会影响父线程读取的一致性 , 在关系型数据库中也被称为不可重复读 。
4、子线程中使用LogicalSetData改变数据槽的值 , 不会影响父线程的数据槽 , 即使他们的key是同一个;
3 .NET Core下没有CallContext
在.NET Core下没有CallContext类 , 取而代之的是使用AsyncLocal代替 , 实现的是CallContext.LogicalGetData 和 CallContext.SetLogicalCallContext 。
例如 , 下面是一个示例代码 , 我们可以借助AsyncLocal来自己实现一个CallContext类 。如果你是将.NET Framework升级为.NET Core , 那么你可能需要自己实现一个CallContext类来代替之前的CallContext:
public static class CallContext{static ConcurrentDictionary<string, AsyncLocal<object>> state = new ConcurrentDictionary<string, AsyncLocal<object>>();public static void SetData(string name, object data) =>state.GetOrAdd(name, _ => new AsyncLocal<object>()).Value = http://hnpxn.com/IT/data;public static object GetData(string name) =>state.TryGetValue(name, out AsyncLocal data) ? data.Value : null;}4EF DbContext场景
对于像UnitOfWork这种操作模式 , 是比较适合于CallContext发挥的地方 , 让EF DbContext在线程上下文内保持唯一 。
注意:这里提到的EF均指EF 而非 EF Core 。
因此 , 我们经常可以看到如下所示的示例代码:
public class DbContextFactory{public static DbContext CreateDbContext(){DbContext dbContext = (DbContext)CallContext.GetData("dbContext");if (dbContext == null){dbContext = new WebAppEntities();CallContext.SetData("dbContext", dbContext);}return dbContext;}}此用法像极了 Cache(缓存)的使用 。
But , 鉴于目前广泛使用线程池的前提 , 线程在处理完一个请求之后 , 并没有被销毁 , 存储在CallContext中的上下文对象也一直存在 , 如果是下一次拿出这个线程去处理另一个请求 , 这个上下文对象其实也在不断的膨胀 , 只不过比全局的膨胀的稍微慢一些 。而且 , 有时候一个线程并不一定是拿去处理请求了 , 如果是服务器拿去处理其他的业务 , 那就可能引发一些其他的问题 。
这时 , 或许我们可以考虑另一个方案 , 在ASP.NET中的HttpContext中有一个Items属性 , 它也可以用来保存key-value , 这就完美了 , 一次请求正好对应着一个HttpContext , 请求结束 , 它自动释放 , EF上下文也就不存在了 。
因此 , 这里把上面代码中的CallContext改为HttpContext.Current.Items:
public class DbContextFactory{public static DbContext CreateDbContext(){DbContext dbContext = HttpContext.Current.Items["dbContext"] as DbContext;if (dbContext == null){dbContext = new WebAppEntities();         HttpContext.Current.Items["dbContext"] = dbContext;}return dbContext;}}其实 , HttpContext这个类和CallContext是有关联的 , 查看源码我们可以发现:HttpContext.Current是通过CallContext.HostContext实现的 。


以上关于本文的内容,仅作参考!温馨提示:如遇健康、疾病相关的问题,请您及时就医或请专业人士给予相关指导!

「四川龙网」www.sichuanlong.com小编还为您精选了以下内容,希望对您有所帮助: