Go E08:双实例租约与重试为何不等于恰好一次
E07的独立消费者可以向累计任务服务提交任务;但原服务在单实例重启时把残留 RUNNING 标为 FAILED,这不等于另一个实例可以安全接手。为把差异变成可复跑的实验,本篇在同一 go_tasks 表与原统计函数旁增加显式的 taskstats lease 教学入口,由独立子进程 A/B 领取同一任务。普通 serve 的恢复策略不变,也不能与该实验模式混跑。源码、原始命令/双流和 PostgreSQL 查询在完整素材包、SHA-256和独立复跑说明中。 RUNNING 需要归属与期限,不能只看状态名 单实例原有 Claim 的 QUEUED → RUNNING 条件更新避免同时领取,却没有记录哪一个进程应完成任务。租约模式在原任务行增加 lease_owner、lease_epoch 与数据库时钟下的 lease_until。领取是一条带条件的 SQL UPDATE RETURNING:只有 QUEUED 或租约已过期的 RUNNING 才能被写成当前 worker 的所有权,并把 epoch 加一。两个连接同时争同一条新任务,十轮 SQL 测试每轮只有一个成功;这是一组已执...
Go E07:workspace 与多 module 能否隐藏依赖
E06在同一个累计任务服务上比较了编译配置。若外部工具也要提交并查询任务,是否应该让它直接导入服务的 main 包?不能:服务包封装了执行器、SQL 和诊断端点,消费者只需要稳定的 HTTP 请求/响应契约。本篇从累计工程中拆出 client/:只实现 Submit、Lookup、Cancel 的薄客户端。它不接触任务状态机,更不会复制 worker。代码、原始双流和真实数据库实验见完整素材包、SHA-256及独立复跑说明。 一个成功的 workspace 构建证明不了依赖闭合 冻结 Go 1.27.1。go help work 规定 go.work 的 use 把列出的 module 当作工作区根模块,并允许工作区替换覆盖模块内的替换。累计工程的 go.work 列出原服务、client/ 和 consumer/;后者声明 require example.com/go-language-task/client v0.1.0,却没有独立的解析途径。GOWORK=auto 从 consumer/ 构建通过,只说明这三份源码在同一个目录树中能协同编译,不说明独立消费者能拿到这个版本。...
Go E06:PGO 在真实负载下有无收益
E05只换了 HTTP 路由器。现在回到原任务服务的实际负载:同一个 Go 1.27.1 工具链,给编译器提供一份代表性 CPU profile,构建 PGO 开关两版程序,然后让真实进程完成同一批任务。完整源码和原始结果在素材包,另有SHA-256及独立复跑说明。 profile 是输入,不是收益证明 下列 profile 与耗时数字来自初版 Linux 实验,原始输出保留在包内 evidence/E06/。2026-10-12 的 Darwin/arm64 补齐复跑使用同一 Go 1.27.1 源码、实际训练 profile 和运行前记录摘要的两版二进制:训练同形负载 off/on 中位 106.838/112.170ms,比值 1.050;留出负载 102.627/113.742ms,比值 1.108,两组均观察到退化。新原始记录位于仓库 writing-plans/go-language/completion/evidence/pgo/;不同平台和轮次的绝对耗时不能互相替换。 固定 BenchmarkTaskAnalyzeContext 已有输入 "Go one...
Kotlin E08:if 表达式怎样走过 FIR 与 JVM 后端
suspend 函数怎样变成可恢复的字节码 固定 Kotlin 编译器源码并对照了 `suspend` 的 JVM 生成物。它重点解释后端为什么需要额外的 continuation、标签与状态字段;想区分前端与后端,不必再次从协程下手。一个普通的可空字段判断,足以展示“类型被分析”“条件被表示”“分支成为 JVM 指令”是三种不同的工作。 选一条已经在工程里运行的表达式 累计工程的 CommandParser.kt 没有为编译器研究改写业务语义: 1234fun textLength(source: TaskTextSource): Int { val captured = source.text return if (captured != null) captured.length else 0} TaskTextSource.text 是自定义 getter。读入局部 val captured 再判断非空,避免在判断后重新调用一个可能返回别的值的 getter。新增 CompilerPhaseBoundaryTest 将 getter 的调用...
Kotlin E07:库升级后旧消费者还能运行吗
Java 调用 Kotlin 时默认参数去哪了 已经验证,默认参数并不会自动让 Java 省略实参;`@JvmOverloads` 才会另生成 Java 能直接调用的重载。库作者一旦放出这个重载,问题就从“现在能否编译”变成“旧调用方带着已有 class 文件升级库之后,还能否链接并保持结果不变”。同样的函数声明,在源码、JVM 符号和业务返回值三个层面有不同的兼容结果。 固定消费者,只替换库 隔离工程 examples/kotlin-language/abi-compat/ 使用 Kotlin/JVM 2.2.21、JDK 21 和 Gradle 8.14,通过 maven-publish 将三个示例版本发布到专用 /tmp Maven 仓库。1.0.0 的库对外提供: 12345object TaskLabels { @JvmStatic @JvmOverloads fun render(id: String, suffix: String = "!"): String = id + suffix} Java 旧消费者...
Kotlin E06:挂起事务究竟等到哪里
换个 Dispatcher,阻塞还在吗 区分挂起与占用线程,事务中途挂起,连接归谁 用同步 JDBC 检查连接所有权。换到 Spring 后,最容易误读的是普通方法拦截器的返回:它看见了 `proceed()` 的返回值,并不等于挂起调用者已经获得业务结果,更不等于事务已经提交。仓库另有 [深入 Spring E06](/2026/10/02/深入-Spring-E06-Kotlin挂起调用事务与上下文边界/) 使用另一套版本和独立实验;本篇只复验 Kotlin 累计工程的边界。 拦截器比调用者先返回 SpringCoroutineTransactionTest 用两个 CompletableDeferred 充当闸门。被代理的 suspend read() 先报告进入,再等待放行。普通 MethodInterceptor 调用 invocation.proceed() 后立即把计数加一;测试在放行之前检查计数已经是 1,而异步调用 caller.isCompleted 仍为 false,放行后 caller.await() 才得到 done。JUnit XML 原始输出: 1S...
Go E05:Web 框架只替换哪一层
E04通过 gRPC 适配原服务。本篇仍在同一个任务服务里做另一项局部替换:给 HTTP 应用端口换路由适配器,不复制任务提交、SQL 领取或 worker。选定 Go 1.27.1 和 github.com/go-chi/chi/v5 v5.3.2,具体依赖及 chi 源码 SHA 随完整实验包交付;另有SHA-256和独立复跑方法。 路由框架不替业务提交状态 taskstats serve 新增 --http-adapter stdlib|chi,缺省仍为原标准库 ServeMux。chi 路由器把 POST /tasks 交给原 taskHTTPService.create,GET /tasks/{id} 与 POST /tasks/{id}/cancel 只把框架取到的 ID 填回 PathValue 再交给原 lookup/cancelTask。因此 JSON/字段限制、队列容量、SQL 写入与终态仲裁还是前 39 章那一份服务。--http-adapter unknown 在监听前退出 2;单独的管理 listener 不随 HTTP 适配器一起放出诊断路由。 把两个...
Kotlin E05:虚拟线程和协程怎样比较同一等待任务
24 将 `suspend` 与实际线程区分开;37 用 JMH 测局部成本。JDK 21 又提供虚拟线程,能在一个看起来同步的调用里执行大量等待。如果只报“创建了多少协程 / 虚拟线程”,没有统一任务和限额,两种计数不能推出服务吞吐,更不能推出取消和资源管理是同一种契约。 这次比较收窄到 320 个合成编号任务,每项等待 8ms,最多允许 32 个任务进入等待段。虚拟线程使用 Executors.newVirtualThreadPerTaskExecutor()、Java Semaphore 和 Thread.sleep;协程使用 async(Dispatchers.Default)、协程 Semaphore.withPermit 和 delay。宿主为四 CPU 的 Linux、Ubuntu OpenJDK 21.0.12.1、Kotlin/coroutines 2.2.21/1.10.2,工具链版本与原始逐轮输出在 writing-plans/kotlin/verification/E05/。都是受控等待,不访问 HTTP、数据库或真实客户端。 先对齐“做了多少事” 每个路...
Kotlin E04:JS 与 Wasm 导出的是同一个接口吗
E02 的 `commonMain` 状态机先在 JVM 与 Node 的 JS 目标上运行;E03 增加 linuxX64 ELF。现在把同一个 `TaskState` 编到 Kotlin/Wasm,是否就能让 JavaScript 客户端不经适配地调用同一组导出?公共业务源码可以一样,生成模块的加载方式、异常对象与异步契约却不自动相同。 本轮固定 Kotlin Multiplatform 2.2.21、Gradle 8.14、JDK 21,在 Node 22.23.2 上直接载入实际生成的 JS 与 Wasm 文件。Wasm 概述在核对时仍注明 Beta;没有浏览器、DOM、WASI 或服务器流量的结果。详细版本、失败构建、四目标 XML 和 Node 客户端断言在 writing-plans/kotlin/verification/E04/。 状态规则共享,导出声明分开放 原 commonMain 的 advanceTask 仍没有 kotlin.js 或 Wasm 导入。构建另外声明 wasmJs { nodejs() },各自的测试目标复用 comm...
Go E04:RPC 与流式调用怎样映射任务期限
E03把受控本地函数接在原服务分析器上。本篇沿用同一个累计任务服务的 HTTP/SQL 状态机,通过真正的 TCP gRPC 提交任务并流式看状态。核心不是给 202 换一种序列化格式,而是把 RPC 调用期限、服务端退出和任务终态分开。完整包、SHA-256、独立复跑随文交付。 先冻住传输约定 固定 Go 1.27.1,gRPC-Go google.golang.org/grpc v1.67.1,protobuf 间接依赖 v1.34.2;go.mod/go.sum 和实际 go list -m all 保留版本闭包。本篇使用 gRPC-Go 的 ServiceDesc 和强制 JSON codec,线协议是 application/grpc+json,并未提供 .proto 或生成跨语言 protobuf 客户端。这能实测同版本 Go 客户端与服务端的 RPC/stream 生命周期,但不能宣称默认 gRPC protobuf 客户端可互通。连接只走 loopback insecure.NewCredentials(),TLS、认证及远程网络为 NOT_RUN。 rpc_ta...















