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

细聊C# AsyncLocal如何在异步间进行数据流转

时间:2023-08-28 09:35:29浏览次数:40  
标签:执行 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/wucy/p/17654645.html

相关文章

  • Leetcode2788——按分隔符拆分字符串
    给你一个字符串数组 words 和一个字符 separator ,请你按 separator 拆分 words 中的每个字符串。返回一个由拆分后的新字符串组成的字符串数组,不包括空字符串 。注意separator 用于决定拆分发生的位置,但它不包含在结果字符串中。拆分可能形成两个以上的字符串。结......
  • React加载组件后自动触发某函数,而不需要点击按钮
    问题在项目中使用了ReactToPrint来实现打印,但是trigger属性中的按钮需要点击才能执行打印。期望能在组件加载完成时自动执行打印方法。解决可在组件加载完成时,通过id获取组件,并执行该组件的click方法。代码如下:importReact,{useRef,useEffect}from'react';//.........
  • WPF使用TextBlock实现查找结果高亮显示
    在应用开发过程中,经常遇到这样的需求:通过关键字查找数据,把带有关键字的数据显示出来,同时在结果中高亮显示关键字。在web开发中,只需在关键字上加一层标签,然后设置标签样式就可以轻松实现。在WPF中显示文本内容通常采用TextBlock控件,也可以采用类似的方式,通过内联流内容元素Run达到......
  • Mac m2 pycharm ide 重置
    如果不小心pycharm信息设置修改了重新安装是没有效果的要不么重装系统,要不恢复设置,要么重置重置如下cd/Users/xxxx/Library/ApplicationSupport/JetBrains/PyCharm2023.2rm-rfPyCharm2023.2......
  • vue-颜色选择器(vColorPicker)
      //安装插件//官网:http://vue-color-picker.rxshc.com/npminstallvcolorpicker-S//main.js中全局引入importvcolorpickerfrom'vcolorpicker'Vue.use(vcolorpicker)//在页面中使用<colorPickerv-model="color"v-on:change="he......
  • ETL之apache hop系列3-hop Server环境部署与客户端发布管道工作流
    前言该文档主要是apachehop2.5的Windows10和Linuxdocker环境部署和客户端发布工作流和管道的相关内容不使用Docker直接使用应用程序包,下载压缩包文件后,需要解压缩文件并使用以下命令启动HopGUI:在Linux上:./hop-gui.sh在Windows上(需要JDK11):Hop-gui.bat一、Windo......
  • Programming abstractions in C阅读笔记:p130-p131
    《ProgrammingAbstractionsInC》学习第52天,p130-p131,总结如下:一、技术总结1.piglatingame通过piglatingame掌握字符复制,指针遍历等操作。/**输入:字符串,这里采用书中坐着自定义的getline函数*/#include<stdio.h>#include<string.h>#include"simpio.h"#def......
  • Newbie_calculations
    拿到这道题是个应用程序,经过上次的经验就跟程序交互了一下,结果根本交互不了,输入什么东西都没有反应然后打开ida分析发现有几个函数还有一堆的操作数,看到这一堆东西就没心思分析了,后面才知道原来就是要简化函数别人的wp一共有sub_291000、sub_291100和sub_291220三个函数,导致......
  • vue3中使用provide/inject
    父组件<template><hello-world/><button@click="changeMessage">按钮</button></template><scriptsetuplang="ts">importHelloWorldfrom"./components/HelloWorld.vue";import{provide,ref......
  • 【算法】用c#实现计算方法中的经典降幂优化策略,减少计算复杂度
    对于给定的数组[x1,x2,x3,…,xn],计算幂的累积:x1^(x2^(x3^(…^xn))的最后一位(十进制)数字。例如,对于数组[3,4,2],您的代码应该返回1,因为3^(4^2)=3^16=43046721。结果的增长得快得令人难以置信。例如,9^(9^9)有超过3.69亿个数字。你计算的lastDigit必须有效地处理这些数字。我们假设0^0=1,并且空列表......