首页 > 编程语言 >细聊C# AsyncLocal如何在异步间进行数据流转--源码探究

细聊C# AsyncLocal如何在异步间进行数据流转--源码探究

时间:2024-09-04 10:38:57浏览次数:8  
标签:执行 Task 异步 C# AsyncLocal 源码 线程 ExecutionContext 上下文

前言#

    在异步编程中,处理异步操作之间的数据流转是一个比较常用的操作。C#异步编程提供了一个强大的工具来解决这个问题,那就是AsyncLocal。它是一个线程本地存储的机制,可以在异步操作之间传递数据。它为我们提供了一种简单而可靠的方式来共享数据,而不必担心线程切换或异步上下文的变化。本文我们将探究AsyncLocal的原理和用法,并进行相关源码解析。探讨它如何在异步操作之间实现数据的流转,以及它是如何在底层工作的。

使用方式#

上面我们提到了AsyncLocal可以在异步操作间传递数据,我们在之前的文章<研究c#异步操作async await状态机的总结>一文中提到过异步操作会涉及到线程切换的问题,接下来通过Task来模拟一个简单异步示例,来看一下它的工作方式是什么样的,以便加深对它的理解,先看一下示例

AsyncLocal<Person> context = new AsyncLocal<Person>();
context.Value = new Person { Id = 1, Name = "张三" };
Console.WriteLine($"Main之前:{context.Value.Name},ThreadId={Thread.CurrentThread.ManagedThreadId}");
await Task.Run(() =>
{
    Console.WriteLine($"Task1之前:{context.Value.Name},ThreadId={Thread.CurrentThread.ManagedThreadId}");
    context.Value.Name = "李四";
    Console.WriteLine($"Task1之后:{context.Value.Name},ThreadId={Thread.CurrentThread.ManagedThreadId}");
});

await Task.Run(() =>
{
    Console.WriteLine($"Task2之前:{context.Value.Name},ThreadId={Thread.CurrentThread.ManagedThreadId}");
    context.Value.Name = "王五";
    Console.WriteLine($"Task2之后:{context.Value.Name},ThreadId={Thread.CurrentThread.ManagedThreadId}");
});
Console.WriteLine($"Main之后:{context.Value.Name},ThreadId={Thread.CurrentThread.ManagedThreadId}");

在上面的示例中,我们创建了一个AsyncLocal实例,并赋值了一个Person对象,然后我们创建了两个Task,分别执行了两个异步操作,并分别修改了AsyncLocal中的Person对象的值,分别在执行异步之前执行异步过程中和执行异步之后打印值来观察变化,执行程序输出结果如下

Main之前:张三,ThreadId=1
Task1之前:张三,ThreadId=4
Task1之后:李四,ThreadId=4
Task2之前:李四,ThreadId=6
Task2之后:王五,ThreadId=6
Main之后:王五,ThreadId=6

从输出结果来看,虽然我们在异步中修改了AsyncLocalPerson对象的值,并且也发生了线程切换。但是它可以在异步操作之间的数据共享和传递,使得我们在异步间进行的数据就和在一个线程里操作数据一样,让我们可以忽略掉其实已经发生了多次线程切换。

探究本质#

通过上面的示例,我们发现AsyncLocal确实可以实现异步之间的数据共享和传递,那么它是如何实现的呢?接下来,我们通过先查看AsyncLocal涉及到的相关源码来探究一下。想弄明白它的流转问题,需要研究两个大方向,一个是AsyncLocal的本身实现,一个是AsyncLocal的流转涉及到的异步或者多线程相关这里涉及到的主要是Task线程池里的相关实现。由于异步相关涉及到了一整个体系,所以但看某一点的时候可能不太容易理解,我们先从AsyncLocal本身入手,然后从Task入手,最后从线程池入手,逐步探究AsyncLocal如何进行数据流转的。但是仍然希望能在阅读本文之前先了解一下设计到该话题的相关文章,先对整体有一个整体的把握

AsyncLocal#

虽然强烈建议先看一下上面推荐的文章,但是在这里我们还是简单介绍一下AsyncLocal的实现,所以这里我们简单介绍一下,方便大家能直观的看到。其实涉及到的比较简单,就是看一下AsyncLocal里涉及到关于Value的操作即可[点击查看AsyncLocal.Value源码

标签:执行,Task,异步,C#,AsyncLocal,源码,线程,ExecutionContext,上下文
From: https://www.cnblogs.com/mq0036/p/18395970

相关文章

  • AP2917远近光一切二双路输出降压恒流驱动IC 5-100V 12W 摩托车灯照明IC
    产品描述AP2917是一款可以一路灯串切换两路灯串的降压恒流驱动器,高效率、外围简单、内置功率管,适用于5-100V输入的高精度降压LED恒流驱动芯片。内置功率管输出最大功率可达12W,最大电流1.2A。AP2917一路灯亮切换两路灯亮,其中一路灯亮可以全亮,可以半亮。AP2917工......
  • 安全: nftables:用describe得到表达式的信息
    例子:ctstate[root@fedora~]#nftdescribectstatectexpression,datatypect_state(conntrackstate)(basetypebitmask,integer),32bitspre-definedsymbolicconstants(inhexadecimal):invalid0x00000001new......
  • 基于Mindformers+mindspore框架在升腾910上进行qwen-7b-chat的lora微调
    基于Mindformers+mindspore框架在昇腾910上进行qwen-7b-chat的8卡lora微调主要参考文档:https://gitee.com/mindspore/mindformers/tree/r1.0/research/qwenSTEP1:环境准备我使用mindformers官方提供的docker镜像进行微调,下载指令:dockerpullswr.cn-central-221.ovaijisuan.......
  • 由C# foreach 和 yield return 源码解读的思考
    前言#    当我们编写C#代码时,经常需要处理大量的数据集合。在传统的方式中,我们往往需要先将整个数据集合加载到内存中,然后再进行操作。但是如果数据集合非常大,这种方式就会导致内存占用过高,甚至可能导致程序崩溃。    C#中的yieldreturn机制可以帮助我们解决这个问......
  • C++成员变量的new操作不应该放在构造函数中
    C++成员变量的new操作不应该放在构造函数中:理由如下:https://blog.csdn.net/lmb1612977696/article/details/77850378#:~:text=C++%E7%B1%BB%E4%B8%AD%E7%9A%84构造函数中尽量不要有new的操作,new的操作可以定义一个Init()来单独处理,代码如下:1classTest{2public:3......
  • ElasticSearch入门到掌握,用心看完这三篇就够了【完结2】
    文章目录二、ElasticSearch详解1.DSL查询文档(1)DSL查询语法分类(2)DSLQuery基本语法(3)查询所有(4)全文检索查询(5)精确查询(6)地理查询(7)复合查询相关性算分fuctionscorebool查询2.搜索结果处理(1)排序(2)分页(3)深度分页问题(4)高亮3.RestClient查询文档(1)查询所有(2)全文检索查询(3......
  • 【北京航空航天大学支持 | JPCS签约独立出版稳定EI检索】第三届航空航天与控制工程国
    2024年第三届航空航天与控制工程国际学术会议(ICoACE2024)将于2024年12月13-15日在江苏省南京市举行。ICoACE2024旨在汇聚全球航空航天和控制工程领域的研究者、工程师、学者和业界领导者,共同探讨最新技术进展、面临的挑战及未来趋势。本次会议的核心议题包括但不限于航空航天......
  • 知识付费小程序源码轻松实现一站式运营,开启知识变现之旅
    技术栈:以下是一个简单的知识付费小程序的示例代码:app.js:小程序的入口文件App({onLaunch:function(){//在小程序启动时执行的代码},globalData:{//存储全局数据userInfo:null//用户信息}})pages/index/index.js:首页的代码//导入必......
  • 取图、壁纸,表情包小程序源码系统搭建,已对接好流量主轻松变现
    取图、壁纸、表情包小程序是近年来在互联网平台上非常流行的一种应用形式,它们为用户提供了便捷的图片、壁纸和表情包获取途径,同时也为小程序开发者带来了收益。技术栈:前端:vue3+uniapp后端:PHP数据库:MySQL//app.jsApp({globalData:{images:[],//图片库w......
  • 运行中的Docker容器获取 .NET项目的Dump文件
    进入容器的shelldockerexec-it容器名称或id/bin/bash使用cd命令进入NETSDK所在文件夹cd/usr/share/dotnet/shared/Microsoft.NETCore.App查看当前SDK版本ls进入指定SDK版本的文件夹cd/usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.33使用SDK文......