开发者生态
morning
对 GPUI 的批评
摘要
Recently, there has been a trend of more desktop GUI apps being built using native rust GUI frameworks. And there are now even well known electron apps getting official rewrites: Discord announced the...
the
and
framework
that
are
state
for
egui
want
desktop
2026-11-09
1 阅读
约6分钟阅读
ByteAtATime
字号:
最近,出现了使用本机 Rust GUI 框架构建更多桌面 GUI 应用程序的趋势。现在甚至有一些知名的电子应用程序也得到了官方重写:Discord 宣布他们的应用程序正在使用 GPUI 进行重写。与此同时,许多正在出版的法学硕士克隆似乎选择了 egui。在这篇文章中,我想解释为什么我不确定这些框架是否是构建的良好基础。简单地说:我相信 GPUI 和 egui 的状态模型对于复杂的桌面应用程序来说都是死胡同。两者都是令人印象深刻的项目,并且它们都有自己的位置。 Zed 确实感觉快速且好用,我自己使用 egui 来调试大量游戏中的界面。但我认为这些框架不应该成为本机桌面应用程序的默认选择。我想提出两个论点:每个 UI 架构最终都需要知道发生了什么变化以及谁依赖它,否则性能特征将无法扩展。一个框架的状态模型不能这么说,它会让应用程序用手说出来,而代价是首先使该框架的 API 语义有吸引力。一旦您承认您想要这种精度,运行一次、带有信号和反应孔的组件就是最简单的 API。披露:我将 GPUI 当前的 Linux 渲染器移植到了 wgpu,我构建了下面使用的基准测试工具,并且我在 zgui 上工作,这是一个出现在图表中的基于信号的 Rust 框架。唯一重要的问题 Raph Levien 引用 Ron Minsky 的话:“每个 UI 框架中都隐藏着某种增量框架。” UI 是状态的函数,状态一次会发生一点变化。但是,如果该函数变得昂贵,您可能需要开始寻找一种更快的方法来从增量状态更改中更新屏幕上的像素。因此,每个框架都必须回答一个问题:当一个值发生变化时,什么会运行?模型 写入运行的内容 谁发现更改 立即 (egui) 所有 UI 代码,下一帧 没有人 Elm (Iced) 所有视图,然后是 diff 差异视图 (GPUI) 没有缓存的每个视图 您使用通知信号,重新运行 (Freya、Compose) 读取它的组件 框架 信号,运行一次 (Floem、Solid、zgui) 读取它的闭包 框架 我理解为什么人们喜欢前三个。没有要同步的状态,状态所在的地方,一个纯 Rust 的渲染函数,没有宏或单独的编译器。我要提出的论点是,这些方法无法扩展,解决根本问题会破坏这些模型简单且易于推理的原因。 GPUI:notify 是 zone.js GPUI 称自己为“混合立即模式和保留模式”框架。它保留实体中的状态。 UI 在渲染函数中定义,更改状态必须触发重新运行。 impl Render for Sidebar { fn render ( & mut self , _ : & mut Window, cx : & mut Context < Self > , ) -> impl IntoElement { let inbox = self .收件箱。读(cx); div () 。子(格式!(“{}未读”,收件箱。未读()))。 Children ( inbox .threads .iter( ) .map( | t | t .title .clone( ) ) ) } } 这是普通的 Rust。您可以使用 if 、 for 和局部变量,并且没有任何奇怪的包装器。状态更改需要显式通知: self 。线程[i]。未读=假; CX.通知 ( ) ; notification携带实体id。由于 Rust 在 &mut 上没有写屏障,GPUI 无法看到哪个字段发生了变化(或者是否有任何变化)。 Angular 团队在 2023 年写了关于 zone.js 的文章:它“只能在可能发生事情时通知我们”,并且“这种方法的扩展性不佳”。通知比区域更精确,因为它命名一个实体,但最终它会做出相同类型的声明。在该 id 以下,GPUI 什么都不知道,因此它会重新渲染不在有效 .cached() 边界后面的每个视图。在实践中,GPUI 经常重新渲染每个视图,因为应用程序作者很少使用 .cached(),并且对布局语义施加了一定的限制。 GPUI 素以“快”着称。虽然常数可能相对较低,但渐近地,它留下了很多东西。因此,我运行了一些基准测试,专门测试大型 UI 中稀疏状态更改的实际成本。在 3,000 个活动行(每行一个缓存视图)中,更改一个标签需要 8.4 毫秒。一次悬停、一次击键以及写入一个与旧值相等的值的成本大致相同,因为成本遵循树而不是更改。每 1,000 个活动行,它会增长约 3 毫秒。将行写为普通元素,如上面的代码所示,相同的标签需要 92 毫秒。手写的相等保护将相等写入时间从 7.9 ms 缩短到 0.9 µs(演示每个调用站点还剩多少时间需要查找)。这并不意味着每个 GPUI 应用程序都很慢,但它显示了状态模型的限制。尤其是对于更昂贵的布局,您在实践中确实会遇到这种情况。 Zed 可能感觉很快,但事实是 Zed 是一个相对简单的应用程序,从 UI 角度来看。该应用程序的 chrome 包含一些按钮,位于 si 中
这篇文章对您有帮助吗?
订阅66必读
每日精选科技资讯,直达你的邮箱