当前位置: 首页 > news >正文

【Coroutines】Implement Lua Coroutine by Kotlin - 2

Last Chapter Link

文章目录

          • Symmetric Coroutines
          • Non-Symmetric Coroutine Sample
          • Symmetric Coroutine Sample
          • How to Implement Symmetric Coroutines
          • Wonderful Tricks
          • Code Design
          • Tail Recursion Optimization
          • Full Sources

Symmetric Coroutines

in last blog, we have talked about how to implement lua-style coroutine

there are two kinds of coroutines, symmetric and non-symmetric

  • symmetric

    when coroutine suspend or complete, execution go back to the point resume it

    that means coroutines have a hierarchical relation of calling

  • non-symmetric

    each coroutine is independent, coroutine can specify where to go when suspend

Non-Symmetric Coroutine Sample

like this, implemented in last blog

package x.coroutinesuspend fun main() {val producer = GlobalScope.launch<Unit, Int>(Dispatchers.new()) {for (i in 1..3)yield(i)return@launch 0}val consumer = GlobalScope.launch<Int, Unit>(Dispatchers.new()) {for (i in 1..3)yield(Unit)return@launch Unit}while (!producer.completed() && !consumer.completed()) {val param1 = producer.resume(Unit)val param2 = consumer.resume(param1)}
}
Symmetric Coroutine Sample

which we will talk about soon in this blog

package x.coroutinesuspend fun main() {lateinit var coroutine1: SymmetricCoroutine<String>lateinit var coroutine2: SymmetricCoroutine<String>lateinit var coroutine3: SymmetricCoroutine<String>coroutine1 = createSymmetric {println("parameter ${getParameter()}")transfer(coroutine3, "d")}coroutine2 = createSymmetric {transfer(coroutine1, "c")}coroutine3 = createSymmetric {println("symmetric start")transfer(coroutine2, "b")transfer(coroutine1, "e")}val main = launchSymmetric(coroutine3, "a")coroutine1.clean()coroutine2.clean()coroutine3.clean()println("symmetric end")
}

each coroutine can randomly goto another coroutine, with a input param carried

How to Implement Symmetric Coroutines

kotlin built-in coroutine is the non-symmetric one

but we can implement symmetric coroutines through non-symmetric ones

obviously transfer is the core api that we need to implement

transfer suspend current coroutine, and resume another coroutine, with a yielded param carried

this point is same to non-symmetric coroutines

the difference is, symmetric coroutine will never go back to previous coroutine

Wonderful Tricks

if we create a implicit main coroutine

when coroutine a want to transfer to coroutine b

it can deliver coroutine b and resume parameter to main coroutine

then let the main coroutine resume coroutine b

that is, a suspend, return back to main, then main resume b

now, it is totally same with the non-symmetric coroutines

the yield result is target coroutine + resume param

Code Design

SymmetricCoroutine hold a Coroutine object, that responsible for execution schedule

when main coroutine calls transfer , it will resume work coroutine and wait for its result

when work coroutine calls transfer , it will yield a TransferContext object as result, then resume main coroutine

TransferContext is composed of next coroutine object and a coroutine resume parameter

when main coroutine received the TransferContext as a result, it will transfer the next coroutine again

internal val coroutine: CoroutineImpl<T, TransferContext<*>?> = CoroutineImpl(context) {block()return@CoroutineImpl null
}
data class TransferContext<T>(val coroutine: SymmetricCoroutine<T>,val parameter: T?
)
private tailrec suspend fun <R> transferInner(other: SymmetricCoroutine<R>, param: Any?) {if (!isMain) {val transferContext = TransferContext(other, param as R)coroutine.yield(transferContext)return}if (!other.isMain()) {val impl = other as SymmetricCoroutineImpl<R>val transferContext = impl.coroutine.resume(param as R)transferContext?.let {transferInner(it.coroutine, it.parameter)}}
}

these are core codes, while the remains are auxiliary, just to fulfill details and offer easy-to-use apis

Tail Recursion Optimization

we notice that, all transfer work in work coroutines

are actually implemented by recursive execution of MainCoroutine.transfer , until all work coroutines finished

when work coroutines works for a long time, calling stack of main coroutine will become bigger and bigger

eventually caused StackOverflowError error

kotlin offers a tailrec keyword to optimize recursive execution

the theroy of tailrec is, use while instead of recursion, to avoid stack size increase

Full Sources
package x.coroutinesuspend fun main() {lateinit var coroutine1: SymmetricCoroutine<String>lateinit var coroutine2: SymmetricCoroutine<String>lateinit var coroutine3: SymmetricCoroutine<String>coroutine1 = createSymmetric {println("parameter ${getParameter()}")transfer(coroutine3, "d")}coroutine2 = createSymmetric {transfer(coroutine1, "c")}coroutine3 = createSymmetric {println("symmetric start")transfer(coroutine2, "b")transfer(coroutine1, "e")}val main = launchSymmetric(coroutine3, "a")coroutine1.clean()coroutine2.clean()coroutine3.clean()println("symmetric end")
}
package x.coroutineimport kotlin.coroutines.EmptyCoroutineContextinterface SymmetricCoroutine<T> {fun isMain(): Booleansuspend fun clean()
}interface SymmetricCoroutineScope<T> {fun getParameter(): Tsuspend fun <R> transfer(other: SymmetricCoroutine<R>, param: R)
}data class TransferContext<T>(val coroutine: SymmetricCoroutine<T>,val parameter: T?
)fun <T> createSymmetric(block: suspend SymmetricCoroutineScope<T>.() -> Unit
): SymmetricCoroutine<T> {return SymmetricCoroutineImpl(EmptyCoroutineContext, block)
}suspend fun <T> launchSymmetric(symmetric: SymmetricCoroutine<T>, param: T
): SymmetricCoroutine<Unit> {val main = SymmetricCoroutineImpl<Unit>(EmptyCoroutineContext) {transfer(symmetric, param)}main.isMain = truemain.coroutine.resume(Unit)return main
}
package x.coroutineimport kotlin.coroutines.CoroutineContextinternal class SymmetricCoroutineImpl<T>(context: CoroutineContext,block: suspend SymmetricCoroutineScope<T>.() -> Unit
) : SymmetricCoroutine<T>, SymmetricCoroutineScope<T> {internal var isMain = falseinternal val coroutine: CoroutineImpl<T, TransferContext<*>?> = CoroutineImpl(context) {block()return@CoroutineImpl null}override fun isMain() = isMainoverride fun getParameter(): T {return coroutine.parameter!!}override suspend fun <R> transfer(other: SymmetricCoroutine<R>, param: R) = transferInner(other, param)private tailrec suspend fun <R> transferInner(other: SymmetricCoroutine<R>, param: Any?) {if (!isMain) {val transferContext = TransferContext(other, param as R)coroutine.yield(transferContext)return}if (!other.isMain()) {val impl = other as SymmetricCoroutineImpl<R>val transferContext = impl.coroutine.resume(param as R)transferContext?.let {transferInner(it.coroutine, it.parameter)}}}override suspend fun clean() {while (!coroutine.completed()) {coroutine.resume(getParameter())}}
}

相关文章:

【Coroutines】Implement Lua Coroutine by Kotlin - 2

Last Chapter Link 文章目录 Symmetric CoroutinesNon-Symmetric Coroutine SampleSymmetric Coroutine SampleHow to Implement Symmetric CoroutinesWonderful TricksCode DesignTail Recursion OptimizationFull Sources Symmetric Coroutines in last blog, we have talk…...

java计算机毕设课设—扫雷游戏(附源码、文章、相关截图、部署视频)

这是什么系统&#xff1f; 资源获取方式再最下方&#xff08;本次10月份活动福利&#xff0c;免费提供下载&#xff0c;自行到对应的方式1下载&#xff0c;csdn的0积分下载&#xff09; java计算机毕设课设—扫雷游戏(附源码、文章、相关截图、部署视频) 基于Java的扫雷游戏…...

AndroidLogger 使用问题

Q1&#xff1a;解压zip后&#xff0c;启动Notepad未看到AndroidLogger工具栏 请检查plugins下安装位置是否正确&#xff0c;必须与下图一致&#xff0c;再确认Notepad 是否为 x64 &#xff1f; Q2&#xff1a;使用 adb 可以显示已连接&#xff0c;但是获取不到日志 暂时不确定问…...

数据库常见面试

8道面试题 目录 目录 7道面试题 1.怎样进行sql优化 4、group by优化 5、limit优化 6、count优化 7、update优化 2.。怎样查看sql执行情况呢(哪个关键字)&#xff0c;说说你对这个关键字的认识 4) possible_key&#xff1a; 5) key 3.说说你对innodb和 myisam的理解 …...

boxplot 绘制箱线图,添加数据点

先看效果图 import matplotlib.pyplot as plt #! 解决不显示的问题&#xff1a;中文设置为宋体格式 plt.rcParams[font.family] ["Times New Roman", SimSun]def plot_boxplot(data_list, out_file, x_custom_labels):# 画图fig, ax plt.subplots(figsize(90, 6…...

用sdkman管理多个jdk切换

前言 最近项目前后端进行升级&#xff0c;需要在jdk8和jdk17两个版本切换。最简单的是通过手动切换&#xff0c;但切换过程太繁琐&#xff0c;修改环境变量&#xff0c;达到切换目的。于是尝试其它解决方案&#xff0c;最终确实使用sdkman工具。 sdkman 是一款面向Java开发者的…...

【AIGC】ChatGPT提示词Prompt高效编写模式:结构化Prompt、提示词生成器与单样本/少样本提示

&#x1f4af;前言 在如今AI技术迅猛发展的背景下&#xff0c;尽管像ChatGPT这样的大型语言模型具备强大的生成能力&#xff0c;但它们的输出质量有时仍难以完全满足我们的预期。为了让ChatGPT生成更加准确、可靠的内容&#xff0c;掌握高效的Prompt编写技巧变得尤为重要。本文…...

反调式实战(有道翻译窗口弹出)

1.添加脚本断点实现源码获取 2.Function构造器构造debugger 因为是窗口被弹出的情况&#xff0c;所以window.closefunction()构造debugger。 3.定位到影响弹出的JavaScript代码片段 反调试思想&#xff1a;置空和替换&#xff0c;所以将其JavaScript进行注释或者删除。 这里主…...

verilog端口使用注意事项

下图存在组合逻辑反馈环&#xff0c;即组合逻辑的输出反馈到输入(赋值的左右2边存在相同的信号)&#xff0c;此种情况会造成系统不稳定。比如在data_in20的情况下&#xff0c;在data_out0 时候&#xff0c;输出的数据会反馈到输入&#xff0c;输入再输出&#xff0c;从而造成不…...

Docker常用命令大全汇总

Docker是一种流行的容器化平台,可以在一个独立的、隔离的环境中构建、部署和运行应用程序。了解Docker常用命令可以帮助我们更高效地管理容器,快速开发和部署应用。本文将整理一系列Docker的常用命令,便于日常使用和学习。 1 Docker基础命令 1.1 启动/停止/重启docker # …...

LVS-DR+Keepalived 高可用群集部署

LVS-DRKeepalived 高可用群集部署 Keepalived 的工作原理LVSKeepalived 高可用群集部署配置负载调度器&#xff08;主、备相同&#xff09;关闭防火墙和核心防护及准备IPVS模块配置keeplived&#xff08;主、备DR 服务器上都要设置&#xff09;启动 ipvsadm 服务调整 proc 响应…...

【elasticsearch】安装和启动

启动 Elasticsearch 并验证其是否成功运行通常涉及以下步骤&#xff1a; 下载和安装 Elasticsearch&#xff1a; 访问 Elasticsearch 官方网站下载页面&#xff1a;https://www.elastic.co/guide/en/elasticsearch/reference/current/install-elasticsearch.html根据你的操作系…...

Golang 逃逸分析(Escape Analysis)理解与实践篇

Golang 逃逸分析&#xff08;Escape Analysis&#xff09;理解与实践篇 文章目录 1.逃逸分析2.相关知识&#xff08;栈、堆、GC分析&#xff09;3.逃逸分析综合-实践 demo 逃逸分析&#xff08;Escape Analysis&#xff09;是编译器在编译期进行的一项优化技术&#xff0c;是Gl…...

React入门 9:React Router

1. 什么是路由 路由&#xff08;routing&#xff09;就是通过互联的网络把信息从源地址传输到目的地址的活动。 以上是中文维基百科对路由的解释。通俗的来讲&#xff0c;把一个地方的信息传输到他想去的目的地的过程&#xff0c;就叫路由。 2. 用代码解释路由 需求&#xff1a…...

MATLAB基础应用精讲-【数模应用】Bland-Altman图(附python和R语言代码实现)

目录 前言 几个高频面试题目 Bland-altman图:如何改变y轴 算法原理 Bland-Altman一致性分析 一致性界限 1. 背景介绍 2. Bland-Altman 法 3. batplot 命令介绍 4. 应用实例 Prism GraphPad实现Bland-Altman图 1.输入数据 2.从数据表中选择Bland-Altman分析 3.检…...

ARM/Linux嵌入式面经(四一):中兴面经

1. 请介绍一下您在嵌入式系统开发中的项目经验。 在嵌入式系统开发领域,我积累了丰富的项目经验,这些经验不仅锻炼了我的技术能力,也让我对嵌入式系统的设计和实现有了更深入的理解。以下是我参与的一个具有代表性的嵌入式系统开发项目的详细介绍: 项目背景 该项目是为一…...

鸿蒙虚拟运行环境

加一个环境变量&#xff1a;%SystemRoot%\System32\Wbem pushd "%~dp0" dir /b %SystemRoot%\servicing\Packages\*Hyper-V*.mum >hyper-v.txt for /f %%i in (findstr /i . hyper-v.txt 2^>nul) do dism /online /norestart /add-package:"%SystemRoot%…...

SpringCloud-Consul

为什么引入 Consul 简介以及安装 控制台 localhost:8500 服务注册与发现 服务端 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-consul-discovery</artifactId><exclusions><exclusio…...

nginx搭建负载均衡

准备工作 两台虚拟机&#xff0c;或者本地启动两个相同应用&#xff0c;在不同的端口上安装好的nginx&#xff0c;在linux上两个版本的hexo&#xff0c;或者其他应用&#xff0c;方便观察是否进行了负载均衡 启动服务 在两台虚拟机上启动项目&#xff0c;这里以hexo为例 服务器…...

灵当CRM data/pdf.php 任意文件读取漏洞复现

0x01 产品简介 灵当CRM是一款专为中小企业打造的智能客户关系管理工具,由上海灵当信息科技有限公司开发并运营。广泛应用于金融、教育、医疗、IT服务、房地产等多个行业领域,帮助企业实现客户个性化管理需求,提升企业竞争力。无论是新客户开拓、老客户维护,还是销售过程管…...

Java 语言特性(面试系列1)

一、面向对象编程 1. 封装&#xff08;Encapsulation&#xff09; 定义&#xff1a;将数据&#xff08;属性&#xff09;和操作数据的方法绑定在一起&#xff0c;通过访问控制符&#xff08;private、protected、public&#xff09;隐藏内部实现细节。示例&#xff1a; public …...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06&#xff08;十亿美元&#xff09;。漏洞扫描服务市场行业预计将从 2024 年的 3.48&#xff08;十亿美元&#xff09;增长到 2032 年的 9.54&#xff08;十亿美元&#xff09;。预测期内漏洞扫描服务市场 CAGR&#xff08;增长率&…...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心&#xff0c;JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例&#xff1a; 1. onclick - 点击事件 当元素被单击时触发&#xff08;左键点击&#xff09; button.onclick function() {alert("按钮被点击了&#xff01;&…...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

AspectJ 在 Android 中的完整使用指南

一、环境配置&#xff08;Gradle 7.0 适配&#xff09; 1. 项目级 build.gradle // 注意&#xff1a;沪江插件已停更&#xff0c;推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

浪潮交换机配置track检测实现高速公路收费网络主备切换NQA

浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求&#xff0c;本次涉及的主要是收费汇聚交换机的配置&#xff0c;浪潮网络设备在高速项目很少&#xff0c;通…...

C#中的CLR属性、依赖属性与附加属性

CLR属性的主要特征 封装性&#xff1a; 隐藏字段的实现细节 提供对字段的受控访问 访问控制&#xff1a; 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性&#xff1a; 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑&#xff1a; 可以…...

HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散

前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说&#xff0c;在叠衣服的过程中&#xff0c;我会带着团队对比各种模型、方法、策略&#xff0c;毕竟针对各个场景始终寻找更优的解决方案&#xff0c;是我个人和我司「七月在线」的职责之一 且个人认为&#xff0c…...