< 返回版块

Mike Tang 发表于 2026-11-10 10:08

改一个标签要 8.4 毫秒

这是一篇评 GPUI 状态模型的文章,作者是 Zortax_。文章比较 immediate、Elm、view 和 signal 这几类做法,看一个值变化以后哪些代码会重跑。Reddit 采集时 301 分、81 条评论。帖子时间是 2026-11-09 02:29 UTC。

作者在文首写了两件事。Discord 宣布用 GPUI 重写客户端。不少 LLM 客户端选了 egui。作者认为这两套状态模型撑不住复杂桌面应用。Zed 用起来快,作者自己也在 Bevy 游戏里用 egui 做调试界面。文章同时写明,作者把 GPUI 当前的 Linux 渲染器移植到了 wgpu,下面的基准测试套件是作者搭的,作者还在做信号式框架 zgui。zgui 仓库在 https://github.com/zortax/zgui 。采集时 214 星、6 个 fork,许可证 Apache-2.0,最近推送是 2026-11-08。Zed 仓库采集时 94598 星、11595 个 fork。

GPUI 自述是 immediate 和 retained 的混合。状态留在 entity 里,界面写在 render 函数里。改状态要显式调用 cx.notify()。notify 带的是 entity id。Rust 的 &mut 没有写屏障,GPUI 看不到改了哪个字段,也看不到有没有真的改动。没有有效 .cached() 边界的 view 会重跑。文章写,应用作者很少用 .cached(),这个缓存对布局语义还有限制,实际经常是每个 view 都重跑。

文章里的数字是稀疏更新的成本。3000 个存活行,每行一个带缓存的 view,改一个标签要 8.4 ms。每多 1000 个存活行,大约再加 3 ms。悬停、按键、写成原值,成本接近,因为成本跟着整棵树走。行如果写成普通元素,同一个标签要 92 ms。手写相等判断以后,写成原值的耗时从 7.9 ms 降到 0.9 µs。

文章接着写,把更新做得更细,会把 GPUI 现在这套 API 拆掉。Longbridge 的 gpui-fast 会在帧之间保留每个 view 的子树。3000 行那个标签从 8.4 ms 降到 3.4 ms。能复用的最小单位仍是 view。要让一个标签单独更新,这个标签自己得是一个 view,带 entity、Render、订阅、一份存下来的值和手写判断。状态归每个 panel 自己管时,一次改动能省 83%。状态改成共享模型以后,同样一帧的 retention 慢 11%。窗口和编辑内容没有变。Zed 团队测到,retention 在普通负载上比关掉慢 1% 到 3%,微基准的收益对不上真实 Zed。Zed 自己的说法是,一个窗口有几十个节点和几千个元素。文本编辑器是自定义元素,绕开了 GPUI 的布局和 view 语义。

nicoburns 的评论有 45 分,问能不能把 Dioxus Native 加进这组基准,并希望看到可运行的基准代码。作者回复有 22 分,写 harness 里已经有,文中数字是 taffy 那次更新之前的一次运行,这周会整理对比仓库。zenware 的评论有 81 分,写不喜欢 React 式模型,但拿掉浏览器引擎以后,就算状态模型还像 React,内存和延迟也会下来。作者回复有 58 分,写浏览器的主要成本在 JS、DOM API、线程模型和进程隔离。GPUI 应用的内存、二进制体积和延迟下限会马上下来。作者同时写,随便写的 GPUI 应用会比随便写的 SolidJS 网页应用更顿。simspelaaja 的评论有 46 分,写文章里有多处 LLM 用语,主题有内容,但分不清哪些句子是作者写的。imbev 的评论有 66 分,写 Elm 回答的是发生了什么,View = f(State) 里的函数可以做成纯函数。作者回复有 25 分,写没有显式的 read 绑定,就只能靠 diff 把新的 view 对上保留下来的渲染状态,这个 diff 是 O(n)。

原文链接:https://blog.zortax.de/posts/a-critique-of-gpui

Cot 0.8 补上事务和迁移回滚

Cot 是一个 Django 风格的 Rust Web 框架,自带 ORM、管理后台、表单、认证和 session。0.8 的发布说明写于 2026 年 11 月 9 日。仓库在 https://github.com/cot-rs/cot 。采集时 1095 星、60 个 fork,许可证 Apache-2.0,最近推送是 2026-11-09。crates.io 上的包名是 cot,当前版本 0.8.0,更新时间 2026-11-09,累计下载 26243,近期下载 2984,16 个版本。Reddit 作者是 m4tx,采集时 6 分、0 条评论。帖子时间是 2026-11-09 23:40 UTC。

ORM 这一版加上事务。Database::begin 开一个事务,后面的 insert、save 和 query! 可以把这个事务当成原来的数据库来传。事务对象在没有 commit 的情况下被 drop,会自动回滚。在事务上再调用 begin,得到的是 savepoint,可以单独提交或回滚。

查询补了排序和文本匹配。order_by 接受一组字段或表达式,各自带 asc 或 desc,还可以用 nulls_first、nulls_last 和 by_values。query! 增加 contains、starts_with、ends_with,以及忽略大小写的 icontains、istarts_with、iends_with。用户输入里的 % 和 _ 会按字面量转义。raw_like 接受 "PKG*US" 这种 glob,再按后端翻译。复杂查询可以走原始 SQL:raw 和 raw_with 执行不返回行的语句,raw_as 和 raw_as_with 把行映射成模型。带 _with 的版本会绑定参数。

迁移可以回滚。cot migration rollback 0002 --dry-run 只打印计划。指定的迁移本身留着,它后面的迁移会被撤掉。跨 app 的依赖会一起撤,比如另一张表的外键指过来。也可以传完整迁移名,或者传 0 撤掉这个 app 的全部迁移。cot migration graph --format mermaid -o migrations.mmd 导出依赖图。

路由器用 matchit 的 radix trie 重写。构建时会拒绝 /foo/{bar} 和 /foo/{baz} 这种有歧义的路由。{*path} 可以匹配剩余路径。reverse! 可以追加 query,值会做百分号编码。新项目默认启用 TrailingSlashMiddleware,GET 和 HEAD 在原路径不匹配、补上斜杠能匹配时会重定向,query string 保留。Redirect::permanent 用 308,Redirect::temporary 用 307。ClientIpAddr 默认取直连对端地址。反代场景在配置里写可信网段和 header:

  • proxies = ["10.0.0.0/8"]
  • headers = ["x-forwarded-for"]

Reddit 发布帖写,这一版去掉 axum,改成直接用 hyper。帖子写,项目没有用到 axum 的高层功能,这次是为了减少依赖和编译时间。配置 TOML 的参考页从源码生成。随这次发布一起放出来的示例是 Hack the Space,地址是 https://hackthespace.mackow.ski/ 。1.0 之前还想要什么,写在 https://github.com/cot-rs/cot/issues/434 。

原文链接:https://mackow.ski/blog/cot-v08-lazily-transactional/

rust-analyzer changelog #353

这是 rust-analyzer 2026 年 11 月 9 日的 changelog #353。rust-analyzer 是给 IDE 用的 Rust 编译器前端。仓库采集时 16976 星、2284 个 fork,许可证 Apache-2.0,最近推送是 2026-11-10。Reddit 转发作者是 WellMakeItSomehow,采集时 29 分、3 条评论。帖子时间是 2026-11-09 15:40 UTC。评论里没有对上具体改动的内容。

新功能里,#21392 给 Linux glibc 发行版打开 jemalloc。#23600 是第一次贡献,加了一个选项,只对带 drop glue 的类型显示隐式 drop 提示。#23558 从欢迎页去掉 Create Rust Project 按钮。诊断新增三项:invalid-pat-path-res、match-inherited-imm-ref-with-mut-ref-pat、unresolved-associated-type,对应 #23583、#23589、#23619。性能项 #23591 对 lang item 做了微优化。

修复里,#23598 让 problem matcher 对上 rustc-unicode 的位置。#23478 和 #23631 补上类型位置的 dyn trait 补全。#23610 让强制转换逻辑对上 rustc。#23608 修了 MIR 求值 panic。#23579 不再给结构体字面量提示到不了的路径。#23615 修了 #[repr(i28)] 补全。#23620 让 destructure_struct_binding 可以作用在通配符模式上。#23592 让 generate_doc_example 可以作用在重导出项上。#23554 修了 move_bounds_to_where_clause 之后 GAT 约束的位置。#23616 修了 apply_demorgan 在类型转换上的 panic。#23602 修了 generate_function 在带泛型时的 panic。内部改动里,#23514 把 expect-test 合进 rust-analyzer 仓库。

原文链接:https://rust-analyzer.github.io/thisweek/2026/11/09/changelog-353.html

tellus 验证器 0 次违规,8 个请求失败

这是一篇讲 tellus 集群故障注入的文章,作者是 Heiko Seeberger。tellus 是跑在 Tokio 上的 actor 框架,带监督、有序 death watch、事件溯源和集群。仓库在 https://github.com/tellus-rs/tellus 。采集时 71 星、3 个 fork,许可证 Apache-2.0,最近推送是 2026-11-09。crates.io 当前版本 0.5.3,更新时间 2026-11-01,累计下载 635。Reddit 作者是 quest_for_7c,采集时 0 分、1 条评论。帖子时间是 2026-11-09 14:01 UTC。作者评论有 1 分,写两个 bug 都出在第一次带集群的发布之前。

演示用 Docker Compose 跑 5 个节点,节点通过同一个 DNS 名互相发现。前面放 Caddy,把 HTTP 请求分到这些节点。每一轮,脚本做一件事:杀掉一个节点,用 SIGTERM 停一个节点,或者把两个节点和另外三个隔开。退出或被杀掉的节点会重启并重新加入。集成测试已经会拉起真实进程,覆盖不到 DNS、容器重启和负载均衡。文章写,两个 bug 都出在这三处。

验证器不会在故障进行时检查成员关系。分区两侧看到的成员不同,这是对的。它等混沌停 30 秒,再检查一次是否恢复。恢复的定义是:每个节点都是成员,都把 5 个节点看成 Up,没有脑裂,每个节点都能找到别人的 actor 并向每个节点发消息。每个节点用 HTTP 提供自己的集群视图,验证器用普通 Rust 把 5 份视图拿来比较。

负载均衡要在故障期间继续应答,所以验证器一直查它。一次请求结束后等 0.5 秒再发下一次。连续失败超过 5 秒才记一次违规。每次失败的请求仍然单独计数。2026 年 10 月一次 45 分钟运行里,违规次数是 0,发出的 5352 个请求里有 8 个失败。

第一个 bug 是违规。分区之后,失败一侧的两个节点几乎同时把自己移出并重启。其中一个查共享 DNS 名时,另一个容器还没起来,所以只看到 4 个节点。tellus-bootstrap-dns 把这次应答缓存了,后面的查询还是旧列表。修复是一行:builder.options_mut().cache_size = 0。文章写,两个 bug 都在 tellus 0.4.0 之前修好,已发布版本不受影响。0.4.0 是第一个带集群的版本。

8 个失败请求对得上混沌日志。5 个紧跟在 kill 后面,3 个紧跟在优雅停机后面,分区后面没有。kill 丢一个请求不意外。SIGTERM 这条路径上,节点已经离开集群,健康检查却继续回 200,直到进程退出。Caddy 还在往它发请求,退出瞬间到达的请求失败。修复是进入 Leaving 阶段后健康检查回 503,并且至少再跑 5 秒,让 Caddy 看到变化。Caddy 也会把失败请求重试到另一个节点。带上这个重试以后,另一次 45 分钟运行里 5400 个验证请求都成功。

文章写,0 次违规不等于集群正确。这套故障没有模拟抖动网络、单向链路、时钟偏移和过载。录演示时终端 UI 在轮询每个节点,1552 个请求里失败了 1 个。去掉终端 UI 的 45 分钟运行没有再出现,原因还没查到。演示代码在 tellus v0.5.3 标签的 tellus-cluster-demo 里。

原文链接:https://heikoseeberger.de/2026-11-09-chaos-verifier/


From Rust中文社区 Mike

社区学习交流平台订阅:

评论区

写评论

还没有评论

1 共 0 条评论, 1 页