为啥大多数 UI 框架都是单线程的?
Posted
技术标签:
【中文标题】为啥大多数 UI 框架都是单线程的?【英文标题】:Why are most UI frameworks single threaded?为什么大多数 UI 框架都是单线程的? 【发布时间】:2011-04-04 21:15:41 【问题描述】:例如,Java Swing 和 android UI 都使用单线程模型,其中单个 UI 线程负责更新所有 UI。是什么让框架设计者选择了一种线程模型而不是另一种?
多线程 UI 模型是否会潜在地为您提供更高的性能,但代价是更复杂?我意识到后者很重要,因为线程相关的错误是讨厌,但我想知道单线程模型除了简单之外是否还有其他优点?
【问题讨论】:
您是否已经研究过 GUI 框架的内部结构? Swing 并不简单,尽管它是单线程的。由于应用程序开发人员也可以做到这一点,因此增加一些复杂性会带来微不足道的好处。 我认为性能是一个重要的历史原因。锁定有开销。 Java 最初的 AWT 实际上是 MT 安全的(以及许多 Java 1.0 的东西),而且这是有代价的。同样在大多数 UI 中,使用单线程绘制屏幕通常是最佳实践(当然有例外) @seand。绘制到屏幕是通过数千个并行线程完成的。所有现代 GUI 现在都构建场景图并让 GPU 使用其几乎无穷无尽的着色器单元对其进行渲染(是对 10 年答案的评论,但它仍然是这个问题的谷歌首页结果,所以我评论)。 【参考方案1】:是什么让框架设计者选择了一种线程模型而不是另一种?
来自the horse's mouth:
AWT 最初是作为普通的 多线程Java库。但是作为 Java 团队查看了体验 使用 AWT 和死锁 人们遇到的种族,我们 开始意识到我们正在制作一个 承诺我们无法遵守。
此分析最终导致其中一个 1997 年 Swing 的设计评审,当时 我们回顾了 AWT 的游戏状态, 和整体行业经验, 我们接受了 Swing 团队的 建议 Swing 应该 只支持非常有限 多线程。
(阅读整篇文章,它非常详细地解释了这个决定,并指出完全相同的问题和最终迁移到单线程模型甚至在 Xerox PARC 更早发生 - 我们认为几乎所有东西都在现代前沿CS是30年前发明的)
不会使用多线程 UI 模型 可能会给你更多的表现 尽管以更复杂为代价?
绝对不会,因为绘制 GUI 和处理用户操作(这是 UI 线程需要做的所有事情)不会成为任何正常 2D 应用程序的瓶颈。
【讨论】:
Internet 存档链接到现已丢失的“马的嘴”博客文章:web.archive.org/web/20160402195655/https://community.oracle.com/…【参考方案2】:多线程 UI 模型是否会潜在地为您提供更高的性能,但会以更高的复杂性为代价?
在大多数情况下不会,而且增加的复杂性在绝大多数情况下弊大于利。您还必须意识到 UI 框架也必须处理底层 OS 模型。当然,它可以绕过模型并将其从程序员那里抽象出来,但在这种情况下根本不值得。
由多个线程临时更新 UI 引起的错误数量将远远超过在大多数情况下毫无意义的性能提升(即使有提升,由于锁定和同步,线程也会带来其自身的相关开销,您实际上可能只是在很多时候使性能变差)。
在这种情况下,最好只在需要时明确使用多个线程。大多数情况下,在 UI 中,您希望所有内容都在一个线程上,而通过使用多个线程,您不会获得太多收益。 UI 交互几乎从来都不是瓶颈。
【讨论】:
好答案。是的,理论上 2 个内核可以以两倍的速度更新 GUI,但这完全忽略了两个线程的同步或锁定,实际上你将不得不做很多次。除非您对同步/锁定很聪明,否则您最终可能会使多线程模型的性能比单线程上的相同模型更差(一旦您最终让它工作)。然后,您的框架中增加了所有复杂性,这最终会导致 SDK 更难使用,从而导致您平台上的应用程序更少。【参考方案3】:不,可能不会。至少当您尝试在 CPU 上运行线程时不会。在 GPU 上已经有很多不同形式的并行处理。不是简单的 GUI 工作,而是花哨的 3D(阴影、反射等)
【讨论】:
【参考方案4】:我认为这完全是为了防止死锁。
Swing 的组件不被认为是线程安全的,它们不一定是因为这个 Event Dispatcher Thread。如果 UI 是多线程的,那么整个应用程序将不得不依赖每个组件以线程安全的方式运行,如果没有,那么在不明确的情况下可能会出现死锁。
所以,这样更安全。
不仅如此,Windows Forms (& .Net)、GTK、Motif 和其他各种产品都选择了相同的设计。我想知道 Java 是否会被它们与之交互的底层操作系统 API 强迫做出这个决定。当然,SWT 是被 Windows 窗体逼入这种境地的。
欲了解更多信息,“EDT”是一个很好的起点http://en.wikipedia.org/wiki/Event_dispatching_thread
对于 .NET,SwingWorker 的等价物称为 BackgroundWorker。
【讨论】:
好吧,这样整个应用程序依赖于每个组件在 EDT 上执行所有与 GUI 相关的工作,如果不这样做,您会得到一个损坏的 GUI。 是的。我想执行高效的 EDT 使用比高效的线程管理更容易。 并不是说我认为 Swing 使它易于管理。我发现记住你什么时候在 EDT 上什么时候不在,这很令人困惑。我似乎记得 Groovy 的 SwingBuilder 使它更容易。对安卓一无所知。无论如何,为您的马嘴回答 +1。【参考方案5】:它们都不再是单线程的了。现代人现在都构建了一个场景图,并在不同的线程中渲染/组合它们。 html 小部件不仅在多个线程中进行布局计算,而且在多个进程中进行。
一般来说,随着 MVVM 模式的广泛使用,它对复杂模型毫无意义。您可以从任何线程更新模型。恕我直言,这是发明它的主要原因,而不是数据绑定参数。
如果仅仅因为鼠标/键/触摸事件都在一个线程中到达,您就可以将其称为单线程,您可以进行哲学辩论。如今,操纵发生在许多地方。 GPU 场景图是用数千个并行着色器渲染的,这如何适用于这个问题?
【讨论】:
【参考方案6】:这是因为 UI 应用程序的性质。
您应该读取输入(鼠标或键盘),调度事件,让它们处理,然后再次绘制屏幕。
尝试在多线程进程上进行。
【讨论】:
在 .NET 中,您可以从任何您想要的线程调用Console.Read/Write
。它只是工作。您还没有真正解释为什么多线程应用程序不属于“UI 应用程序的性质”以上是关于为啥大多数 UI 框架都是单线程的?的主要内容,如果未能解决你的问题,请参考以下文章