千家信息网

C#怎么使用CallContext缓存线程数据

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,本篇内容主要讲解"C#怎么使用CallContext缓存线程数据",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"C#怎么使用CallContext缓存线程数
千家信息网最后更新 2026年11月01日C#怎么使用CallContext缓存线程数据

本篇内容主要讲解"C#怎么使用CallContext缓存线程数据",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"C#怎么使用CallContext缓存线程数据"吧!

一、CallContext 概述

命名空间:System.Runtime.Remoting.Messaging

CallContext 用于提供与执行代码路径一起传送的属性集,直白讲就是:提供线程(多线程/单线程)代码执行路径中数据传递的能力。

当对另一个 AppDomain 中的对象进行远程方法调用时,CallContext 类将生成一个与该远程调用一起传播的 LogicalCallContext 实例。只有公开 ILogicalThreadAffinative 接口并存储在 CallContext 中的对象被在 LogicalCallContext 中传播到 AppDomain 外部。

CallContext成员

  • SetData: 存储给定的对象并将其与指定名称关联。

  • GetData: 从CallContext中检索具有指定名称的对象

  • LogicalSetData: 将给定的对象存储在逻辑调用上下文,并将其与指定名称关联。可用于多线程环境

  • LogicalGetData: 从逻辑调用上下文中检索具有指定名称的对象。可用于多线程环境

  • FreeNamedDataSlot: 清空具有指定名称的数据槽。可用于多线程环境

  • HostContext属性: 获取或设置与当前线程相关联的主机上下文。在Web环境下等于System.Web.HttpContext.Current

GetData、SetData

  • 只能用于单线程环境,如果发生了线程切换,存储的数据也会随之丢失

  • 可以用于同一线程中的不同地方,传递数据

LogicalSetData、LogicalGetData

  • LogicalSetData、LogicalGetData可用于在多线程环境下传递数据;

  • LogicalSetData只是存储当前线程以及子线程的数据槽

  • LogicalGetData获取的是当前线程或父线程的数据槽对象,拿到的是对象的引用

  • FreeNamedDataSlot清除当前线程,之前已经运行子任务,不受影响,不能清除子线程的数据槽;

二、 CallContext不跨线程传播的方法:GetData、SetData

可以利用CallContext 实现单例,默认情况下,CallContext 的数据不跨线程传播。

1、在处理多组件共用Context时非常有用,比如常见的EF 可以将实例的DBEntity存储在其中,可以一次访问只实例化一次,便于管理且不用多次实例访问对象

public static class DbContextHelper{    private static DbContext context = null;    private const string SessionKey_DbContext = "Entities";    public static DbContext GetDbContext()    {        if (CallContext.GetData(SessionKey_DbContext) == null)        {            CallContext.SetData(SessionKey_DbContext, new Entities());        }        return CallContext.GetData(SessionKey_DbContext) as Entities;    }}

2、类单例

void Main(){    MyAppContext.Current.FirstName = "a";    Console.Write(MyAppContext.Current.FirstName);}public class MyAppContext{    const string contextKey = "MyAppContext:ContextKey";    public string FirstName { get; set; }    public static MyAppContext Current    {        get        {            if (CallContext.GetData(contextKey) == null)            {                CallContext.SetData(contextKey, new MyAppContext());            }            return CallContext.GetData(SessionKey_DbContext) as MyAppContext;        }    }}

三、 CallContext跨线程传播的方法:ILogicalSetData、LogicalGetData

要让CallContext实现跨线程传播,可以调用CallContext的静态方法ILogicalSetData,或让上下文类实现ILogicalThreadAffinative 接口。

线程本地存储

线程池可能不会释放使用过的线程,导致多次执行之间可能共享数据(可以每次执行前重置线程本地存储的数据)。

for (var i = 0; i < 10; i++){    Thread.Sleep(10);    Task.Run(() =>    {        var slot = Thread.GetNamedDataSlot("test");        if (slot == null)        {            Thread.AllocateNamedDataSlot("test");        }        if (Thread.GetData(slot) == null)        {            Thread.SetData(slot, DateTime.Now.Millisecond);        }        Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + Thread.GetData(slot));    });}

结果

调用上下文

每次执行的数据是完全隔离的,非常符合我们的期望。但是,如果我们期望调用期间又开启了一个子线程,如何让子线程访问父线程的数据呢?这就需要使用到:"逻辑调用上下文"。

Console.WriteLine("测试:CallContext.SetData");for (var i = 0; i < 10; i++){    Thread.Sleep(10);    Task.Run(() =>    {        if (CallContext.GetData("test") == null)        {            CallContext.SetData("test", DateTime.Now.Millisecond);        }        Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + CallContext.GetData("test"));    });}

结果

每次执行的数据是完全隔离的,非常符合我们的期望。

逻辑调用上下文

如果我们期望调用期间又开启了一个子线程,如何让子线程访问父线程的数据呢?这就需要使用到:"逻辑调用上下文"。

注意 ExecutionContext.SuppressFlow(); 和ExecutionContext.RestoreFlow();它们分别能阻止传播和重置传播,默认是允许传播的。

Console.WriteLine("测试:CallContext.SetData");Task.Run(() =>{    CallContext.SetData("test", "段光伟");    Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + CallContext.GetData("test"));    Task.Run(() =>    {        Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + CallContext.GetData("test"));    });});Thread.Sleep(100);Console.WriteLine("测试:CallContext.LogicalSetData");Task.Run(() =>{    CallContext.LogicalSetData("test", "段光伟");    Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + CallContext.LogicalGetData("test"));    Task.Run(() =>    {        Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + CallContext.LogicalGetData("test"));    });    ExecutionContext.SuppressFlow();    Task.Run(() =>    {        Console.WriteLine("SuppressFlow 之后:" + CallContext.LogicalGetData("test"));    });    ExecutionContext.RestoreFlow();    Task.Run(() =>    {        Console.WriteLine("RestoreFlow 之后:" + CallContext.LogicalGetData("test"));    });});

输出

四、Web中的CallContext

HttpContext.Current(包括Session)的存储是基于当前线程的CallContext,在非请求处理线程(即其他线程)是无法获取当前HttpContext的(不跨线程传播)。

到此,相信大家对"C#怎么使用CallContext缓存线程数据"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

线程 数据 传播 对象 存储 上下 上下文 环境 名称 方法 逻辑 实例 期望 缓存 C# 关联 测试 个子 代码 内容 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 百单网互联网科技有限公司怎么样 互联网科技官网 互联网科技公司的优势 互联网 的科技创新 以房互联网科技 齐家互联网科技 迪茉互联网科技 互联网汽车科技小镇 农村开互联网科技讲堂 苏州铭阳互联网科技有限公司 电子科技大学互联网创业大赛 亳州好赞互联网科技有限公司 上海京穆互联网科技有限公司 2021互联网科技公司排名 本届互联网大会上的黑科技 工业互联网科技成果转化 半导体行业属于互联网高科技类吗 艺电能源互联网科技有限公司招聘 马化腾互联网科技教学 北京品多多互联网科技有限公司 百单网互联网科技有限公司怎么样 善班互联网科技有限公司 科技赋能互联网健康 中国的互联网科技企业的崛起 互联网为啥属于高科技 互联网时代的科技公司 万物互联网智能科技 恒生互联网科技趋势 瑞安市蟠桃会互联网科技有限公司 科技美学互联网 艺术
0