ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

text-to-cad并发构建保护机制:锁等待与竞态处理的工程设计细节

text-to-cad并发构建保护机制:锁等待与竞态处理的工程设计细节 text-to-cad并发构建保护机制锁等待与竞态处理的工程设计细节【免费下载链接】text-to-cadA library of agent skills for CAD, CAE and CAM项目地址: https://gitcode.com/GitHub_Trending/tex/text-to-cadtext-to-cad 是一个面向 CAD、CAE 和 CAM 的 AI Agent 技能库它最大的特色之一是如何在多进程同时构建同一个模型时用一套锁等待 竞态处理机制保护构建过程不互相踩踏。这篇文章带你读懂它的并发保护设计从内核级 flock 锁到超时降级每一环都藏着工程取舍。为什么 CAD 工作流里并发构建是定时炸弹用 Agent 生成 CAD 模型时很容易出现这样的场景你在 CLI 里跑了一次gen构建AI 同时在 Viewer 里触发同一模型的构建一次构建动辄几分钟OCP 网格化期间 GIL 会被长时间占用两个进程如果同时写入同一目录读者就会看到一个写到一半的半成品包text-to-cad 的解法在 cadgen/coordination 包里生产端构建进程和读取端Viewer 服务器共享同一套协议而不是各写一份。三个协调文件哨兵与状态记录长什么样每个产物的输出目录旁都有一组隐藏兄弟文件定义在 coordination/paths.py 中。以输出目录folder/__cadgen__/models/widget.step为例.name.step.generation.lock 写者哨兵构建时持有 .name.step.generator.lock 生成器哨兵导出等不写包的操作持有 .name.step.generation.progress.json 状态记录进度 JSON两个哨兵文件是刻意为之构建要重写整个包而导出STL/GLB 等只占用生成器、写到别处。读者由此能区分**模型正在被重写必须隐藏磁盘上的旧产物和生成器忙**旧产物仍可用。内核托管的 flock 锁为什么放弃心跳状态文件coordination/lock.py 的模块头注释几乎就是一份事故复盘。早期版本用{pid, status, startedAt}JSON 状态文件 1 秒心跳线程判断构建是否存活结果暴露了三个致命缺陷缺陷后果状态文件只被写入、从未被获取两个并发构建各自放行先完成的一方删掉共享文件时另一个还在写——读者在半成品上看到无构建中用os.kill(pid, 0) 30 秒心跳窗口推断存活网格化长时间持有 GIL心跳线程饿死健康构建被误判为已死生产端从不互相等待只有 Viewer 等待并发写入直接竞争同一目录新设计只有一条铁律锁状态归内核所有——进程崩溃或被 kill 时内核随文件描述符关闭自动释放锁。代码里明确写着No liveness inference lives here, and none may be added不做 pid 检查、不做心跳、不做时间窗推断。还有一个精巧的细节读侧探测用共享锁LOCK_SH、写侧用排他锁LOCK_EX。因为flock是按打开文件描述计冲突而非按进程若两个读者都用LOCK_EX探测会彼此误报有构建在飞——修复前 4 线程并发下实测约 6% 的误报率。锁等待与超时--lock-timeout的设计取舍CLI 的并发策略在 _internal/cli_locking.py 中默认无限等待WAIT_FOREVER 0.0Agent 发起构建就是要产物直接放弃只会留下没构建、也没办法的空手结果排队等待才是正解Viewer 必须不阻塞它作为常驻服务显式传入超时超时后不抛错而是返回{ok: true, contended: true}——没错只是模型正在被别处构建等待期间还有一个体感设计on_wait回调在等待超过 0.25 秒后首次播报、之后每 30 秒重复一次waiting for another run to finish building ...。没有它一个排队中的构建在两个流上都不输出任何内容和进程挂死完全无法区分见 lock.py 的 _acquire。 使用层面SKILL.md 里写得很直白——构建会等待同一模型的并发构建并持续在 stderr 播报加--lock-timeout SECONDS可改为放弃等待此时该目标的 outcome 是contended而不是built参见 skills/cad/SKILL.md。旧进程残留的进度条runId 归属机制崩溃的构建会留下一份非终态的状态记录在磁盘上。如果没有识别手段Viewer 会把一具尸体的进度渲染成当前构建的位置——比如显示Meshing components 31/50而当前构建其实一个组件都没网格化。解法在 coordination/record.py拿到锁时先在哨兵里盖上本次运行的 runIdUUID读者只渲染 runId 与当前持锁者一致的状态记录。归属不匹配、schema 版本不认识、记录已终态——一律显示无进度安全降级。写入侧同样是原子的临时文件名带 pid 防多进程互踩再os.replace落盘轮询读者永远不会读到半截 JSON。优雅降级锁不可用构建也绝不能失败这套机制有一条贯穿始终的底线策略——a build must never fail because a lock was unavailable无fcntl/msvcrt、目录不可写、NFS/SMB 等不支持咨询锁的文件系统统统降级为无协调照常构建状态记录写不进去降级为无进度上报绝不因此失败在 Windows 的msvcrt区域锁上空哨兵无法加锁越过 EOF 加锁是错误于是一个open 后、写 runId 前崩溃的空哨兵被报告为降级而非被持有避免永久卡死后续所有构建文件重命名在 SMB 上的共享冲突WinError 32由 atomic_replace.py 做 350ms 内的有界重试但权限类错误立即上报——重试只留给服务器还没跟上这一种情况值得借鉴的三个设计思想权威来源唯一谁活着只问内核状态文件只是装饰永远不承担存活判断等待是默认放弃是显式选择把排队作为生产端默认语义把超时放弃留给必须不阻塞的调用方失败模式先于功能设计每个环节探测、加锁、写记录、重命名都先回答如果这里不可用构建是否还能成功 想深入源码核心路径锁原语coordination/lock.py文件布局coordination/paths.py状态记录coordination/record.pyCLI 超时与等待播报_internal/cli_locking.py原子替换_internal/atomic_replace.py【免费下载链接】text-to-cadA library of agent skills for CAD, CAE and CAM项目地址: https://gitcode.com/GitHub_Trending/tex/text-to-cad创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表