ET9中ETTask传递新的Context原理

news2024/11/26 9:16:15

ET9中ETTask传递新的Context原理

前言

每一个异步函数都会创建两个对象,
1个是当前异步函数返回值(ETTASK)对应的ETAsyncTaskMethodBuilder,通过这个类的静态方法Create创建返回,这个builder类中会有一个Task对象,用于当返回值返回;
2个是编译器为我们创建的对应的状态机对象。其中状态机对象包裹了当前异步函数的所有代码。
在这里插入图片描述

对应的源码
在这里插入图片描述
以及包裹的状态机代码:
在这里插入图片描述

一、ETTask传递上下文的关键代码

如上图中红框所示,只要在源码中调用了await,就会执行对应的ETAsyncTaskMethodBuilder的AwaitUnsafeOnCompleted函数,这里就是传递上下文的入口。在一个异步函数(父异步)中,每次await调用另外一个异步函数(称为子异步吧),都会获得这个子异步函数对应的builder中的Task,又是通过父异步函数的builder对象的AwaitUnsafeOnCompleted来实现的。所以此时可以拿到此时父异步函数builder中的Task的上下文对象,传递给AwaitUnsafeOnCompleted中的子异步函数builder返回的builder中的Task。
ET9中的源码:

public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine
        {
            this.iStateMachineWrap ??= StateMachineWrap<TStateMachine>.Fetch(ref stateMachine);
            awaiter.UnsafeOnCompleted(this.iStateMachineWrap.MoveNext);
            
            if (awaiter is not IETTask task)
            {
                return;
            }
            
            if (this.tcs.TaskType == TaskType.WithContext)
            {
                task.SetContext(this.tcs.Context);
                return;
            }
            
            this.tcs.Context = task;
        }

可以看到获取当前tcs(也就是builder中的Task)的类型是附带有上下文的,那么就进行一次设置子Task的上下文设置,如果不是携带上下文,就把当前Task上下文设置为这个子Task,用于后续上下文传递。
SetContext这是个Task的扩展函数,内部是循环,设置当前Task的上下文同时,找到对应的子Task,如果子Task不存在,或者已经是附带上下文了,就返回。

while (true)
            {
                if (task.TaskType == TaskType.ContextTask)
                {
                    ((ETTask<object>)task).SetResult(context);
                    break;
                }

                // cancellationToken传下去
                task.TaskType = TaskType.WithContext;
                object child = task.Context;
                task.Context = context;
                task = child as IETTask;
                if (task == null)
                {
                    break;
                }
                 传递到WithContext为止,因为可能这一层设置了新的context
                if (task.TaskType == TaskType.WithContext)
                {
                    break;
                }
            }

通过上面的代码,就可以理解为,当前异步函数中,只要await了一个ETTask,那么就会把当前异步函数ETTask(由对应的builder创建的)的上下文,传递给这个ETTask(没有设置自己的上下文),无论这个ETTask是由新的异步函数创建返回的,还是我们手动ETTask.Create的。

二、GetContextAsync怎么获取到当前上下文的

有了上面的介绍,我们就能知道,ETTask的上下文如何进行传递的。那么在一个异步函数中,要获取当前异步函数的上下文,那么就可以await ETTaskHelper.GetContextAsync来获取。
源码如下:

public static async ETTask<T> GetContextAsync<T>() where T: class
        {
            ETTask<object> tcs = ETTask<object>.Create(true);
            tcs.TaskType = TaskType.ContextTask;
            object ret = await tcs;
            if (ret == null)
            {
                return null;
            }
            return (T)ret;
        }

当一个异步函数await这个GetContextAsync,那么进入这个函数时,外层的异步函数的ETTask上下文就传递到这个异步函数中(强调一下,由这个异步函数对应的Builder的创建的ETTask中)。然后内部创建了一个ETTask,再一次Await,那么上下文就由builder的Task传递到内部这个创建的ETTask。
要注意的是,内部创建的ETTask类型是ContextTask,那么在await–>AwaitUnsafeOnCompleted->SetContext,最终调用到SetContext时,有如下代码:

			if (task.TaskType == TaskType.ContextTask)
                {
                    ((ETTask<object>)task).SetResult(context);
                    break;
                }

即立刻调用此ETTask的SetResult的结果为上下文,然后ETTask会调用callback(由AwaitUnsafeOnCompleted传给ETTask的,状态机的MoveNext委托),就会返回到GetContextAsync函数中,获取结果并返回,这个结果就是当前异步函数的上下文信息了。

总结

ET9作者猫大的创新以及设计能力确实强,新版的ETTask也确实牛逼,有了上下文确实能搞出很多花样了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1871688.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

003GeoGebra如何无缝嵌入到PPT里

GeoGebra无缝嵌入到PPT里真是一个头疼的问题&#xff0c;已成功解决&#xff0c;这里记录一下&#xff0c;希望可以帮助到更多人。 注意&#xff0c;后续所有的文章说的PPT都是Offce Power Point, 不要拿着WPS的bug来问我哦&#xff0c;我已经戒WPS了&#xff08;此处表示无奈&…

shell 脚本中断问题定位

shell 脚本中断问题定位 1 介绍2 定位方法2.1 查看脚本的退出状态码2.2 查看系统日志文件2.3 使用journalctl工具2.4 使用dmesg命令2.5 检查脚本自身的日志记录2.6 使用图形界面工具2.7 配置和使用集中式日志管理系统 参考 1 介绍 shell 脚本运行&#xff0c;一段时间后&#…

视频编解码从H.264到H.266:浅析GB28181安防视频汇聚EasyCVR视频压缩技术

随着信息技术的飞速发展&#xff0c;视频编解码技术也在不断革新&#xff0c;以适应高清、超高清甚至8K视频时代的到来。视频编解码技术作为数字多媒体领域的核心技术之一&#xff0c;也在不断地演进和革新。从早期的H.261到现在的H.265、H.266&#xff0c;每一次技术的升级都极…

lambda-map.merge

map.merge 结论: 1.当前传入的 key ,value biFunction 2.如果之前map不存在则直接put(当前key,当前value) 3.如果之前map已经有了,老value与 当前value 进入function处理后再 put(当前key,处理后的value)

【YOLOv5/v7改进系列】引入RT-DETR的RepC3

一、导言 RT-DETR&#xff08;Real-Time Detection Transformer&#xff09;是一种针对实时目标检测任务的创新方法&#xff0c;它旨在克服YOLO系列和其他基于Transformer的检测器存在的局限性。RT-DETR的主要优点包括&#xff1a; 无NMS&#xff08;非极大值抑制&#xff09;…

基于LMS自适应滤波的窄带信号宽带噪声去除(MATLAB R2021B)

数十年的研究极大的发展了自适应滤波理论&#xff0c;自适应滤波理论已经成为信号处理领域研究的热点之一。从理论上讲&#xff0c;自适应滤波问题没有唯一解。为了得到自适应滤波器及其应用系统&#xff0c;可以根据不同的优化准则推导出许多不同的自适应理论。目前该理论主要…

youlai-boot项目的学习(4) 前后端本地部署

环境 1、macOS, brew, IntelliJ IDEA, WebStrom 2、后端&#xff1a;https://gitee.com/youlaiorg/youlai-boot.git , master, 9a753a2e94985ed4cbbf214156ca035082e02723 3、前端&#xff1a;https://gitee.com/youlaiorg/vue3-element-admin.git, master, 66b913ef01dc880ad…

嵌入式Linux系统编程 — 4.1 字符串输入输出

目录 1 字符串输出 1.1 字符串输出函数简介 1.2 示例程序 2 字符串输入 2.1 字符串输入简介 2.2 示例程序 程序运行时&#xff0c;需打印信息至标准输出 stdout 设备 或标准错误 stderr设备&#xff08;譬如屏幕&#xff09;&#xff0c;如调试信息、报错信息、中间产生的…

hnust 1817 算法10-10,10-11:堆排序

hnust 1817 算法10-10,10-11&#xff1a;堆排序 题目描述 堆排序是一种利用堆结构进行排序的方法&#xff0c;它只需要一个记录大小的辅助空间&#xff0c;每个待排序的记录仅需要占用一个存储空间。 首先建立小根堆或大根堆&#xff0c;然后通过利用堆的性质即堆顶的元素是最…

NDT(基于正态分布变换的配准算法)

NDT是将单个扫描的离散点集转换为空间上定义的分段连续可微概率密度&#xff0c;该概率密度由一组易于计算的正态分布组成的算法。采用NDT连续化后&#xff0c;传统硬离散优化问题能够潜在地转化为更易于处理的连续优化问题。 NDT原理 NDT将根据点云中点所处的位置&#xff0…

一款开源、免费、现代化风格的WPF UI控件库

前言 今天大姚给大家分享一款开源&#xff08;MIT License&#xff09;、免费、现代化风格的WPF UI控件库&#xff1a;ModernWpf。 项目介绍 ModernWpf是一个开源项目&#xff0c;它为 WPF 提供了一组现代化的控件和主题&#xff0c;使开发人员能够创建具有现代外观的桌面应…

Linux的fread函数

fread函数 从文件中读入数据到指定的地址中 函数原型 : size_t fread(void*buff , size_t size, size_t count , FILE* stream) /* * description : 对已打开的流进行数据读取 * param ‐ ptr &#xff1a;指向 数据块的指针 * param ‐ size &#xff1a;指定读取的每…

GuLi商城-商品服务-API-三级分类-删除-页面效果

一步步学习Vue太慢了&#xff0c;准备跳过前端的学习&#xff0c;直接使用前端完整的项目 下载依赖npm install&#xff0c;会报错&#xff0c;排查了好久 我安装的是Node14&#xff0c;所以必须要安装4.14 Vscode终端输入&#xff1a;npm install node-sass4.14 输入&#x…

snat、dnat和firewalld

snat &#xff1a;源地址转换 内网——外网 内网ip转换成可以访问外网的ip 也就是内网的多个主机可以只有一个有效的公网ip地址访问外部网络 DNAT&#xff1a;目的地址转发 外部用户&#xff0c;可以通过一个公网地址访问服务内部的私网服务 也就是私网的IP和公网IP做一个…

Golang | Leetcode Golang题解之第202题快乐数

题目&#xff1a; 题解&#xff1a; func isHappy(n int) bool {cycle : map[int]bool{4: true, 6: true, 37: true, 58: true, 89: true, 145: true, 42: true, 20: true}for n ! 1 && !cycle[n] {n step(n)}return n 1 }func step(n int) int {sum : 0for n > …

亚马逊AI技术风波:人工智能“洗白”现象引发质疑

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

基于RabbitMQ的异步消息传递:发送与消费

引言 RabbitMQ是一个流行的开源消息代理&#xff0c;用于在分布式系统中实现异步消息传递。它基于Erlang语言编写&#xff0c;具有高可用性和可伸缩性。在本文中&#xff0c;我们将探讨如何在Python中使用RabbitMQ进行消息发送和消费。 安装RabbitMQ 在 Ubuntu 上安装 Rabbi…

stm32中IIC通讯协议

参考资料&#xff1a;大部分均引用b站江协科技课程、GPT及网络资料 什么是IIC&#xff08;i2C&#xff09;通讯协议&#xff1f; 关键字&#xff1a;SCL、SDA、半双工、同步、串行。 IIC&#xff08;Inter-Integrated Circuit&#xff09;&#xff0c;也称为I2C&#xff08;In…

vue2 element ui 表单 动态增加表单项 表单项值不可重复 select多选

案例 <template><el-form :model"form" ref"form" label-width"70px"><el-form-item><el-button icon"el-icon-plus" type"primary" plain click"add">新增</el-button><el-b…

22 Shell编程之免交互

目录 22.1 Here Document免交互 22.1.1 Here Document概述 22.1.2 Here Document免交互 22.1.3 Here Document变量设定 22.1.4 Here Document格式控制 22.1.5 Here Document多行注释 22.2 expect免交互 22.2.1 expect概述 22.2.2 expect安装 22.2.3 基本命令介绍 22.2.4expec…