以前曾提出过密切相关的问题:
但这些问题的答案仍然让我不清楚某些问题。
第一个问题的提问者询问多线程是否有助于提高性能,而回答者大多表示不会这样做,因为GUI不太可能成为现代硬件上2D应用程序的瓶颈。但在我看来,这是一个偷偷摸摸的辩论策略。当然,如果您仔细构建了应用程序,除了UI线程上的UI调用之外什么都不做,那么您就不会遇到瓶颈。但这可能会花费大量工作并使您的代码更复杂,如果您有更快的内核或可以从多个线程进行UI调用,也许它不值得做。
一个普遍提倡的建筑设计是让视图组件没有回调,除了他们的后代之外不需要锁定任何东西。在这样的架构下,你不能让任何线程使用每个对象的锁来调用视图对象上的方法,而不用担心死锁吗?
我对UI控件的情况不太自信,但只要它们的回调仅由系统调用,为什么它们会导致任何特殊死锁问题?毕竟,如果回调需要耗费任何时间,他们将委托给另一个线程,然后我们回到多线程案例中。
如果您只是阻止UI线程,您将获得多线程UI的多少好处?因为异步的各种新兴抽象实际上允许你这样做。
我所看到的几乎所有讨论都假设使用手动锁定来处理并发性,但人们普遍认为手动锁定是在大多数情况下管理并发性的一种不好的方法。当我们考虑专家建议我们使用更多的并发原语(例如软件事务内存)或避免共享内存以支持消息传递(可能具有同步,如go)时,讨论如何改变?
答案 0 :(得分:15)
<强> TL; DR 强>
这是一种强制排序在一个最终将按顺序排列的活动中的简单方法(屏幕按顺序每秒抽取X次)。
<强>讨论强>
处理在系统中具有单一标识的长期资源通常通过使用单个线程,进程,“对象”或其他代表关于给定语言的并发性的原子单元来表示它们来完成。回到非限制性,疏忽内核,非时间共享,One True Thread日,这是通过轮询/循环或编写自己的调度系统来手动管理的。在这样的系统中,你仍然在function / object / thingy和singular资源之间有一个1 :: 1的映射(或者你在8年级之前就疯了)。
这与处理网络套接字或任何其他长期资源时使用的方法相同。 GUI本身只是典型程序管理的众多此类资源之一,通常长期存在的资源是事件排序很重要的地方。
例如,在聊天程序中,您通常不会编写单个线程。你会有一个GUI线程,一个网络线程,也许还有一些其他线程来处理日志记录资源或其他什么。典型系统如此之快以至于更容易将日志记录和输入放入进行GUI更新的同一线程中并不少见,但情况并非总是如此。但是,在所有情况下,每种类别的资源最容易通过授予它们一个线程来推理,这意味着网络的一个线程,GUI的一个线程,以及许多其他线程对于长期操作或要管理的资源不会阻挡其他资源。
为了让生活变得更轻松,不的共同点就是尽可能直接在这些线程之间共享数据。队列比资源锁更容易推理并且可以保证排序。大多数GUI库要么对要处理的事件进行排队(因此可以按顺序对它们进行求值),要么立即提交事件所需的数据更改,但在重新绘制循环的每次传递之前都要锁定GUI的状态。以前发生的事情并不重要,绘制屏幕时唯一重要的是世界状态然后。这与典型的网络情况略有不同,在这种情况下,所有数据都需要按顺序发送,而忘记其中一些数据不是一种选择。
因此,GUI框架本身并不是多线程的,它本身就是一个GUI循环,它需要是一个单独的线程才能理智地管理这个单一的长期资源。编程示例(通常本质上是微不足道的)通常是单线程的,所有程序逻辑都在与GUI循环相同的进程/线程中运行,但这在更复杂的程序中并不常见。
总结
由于调度很难,共享数据管理更难,单个资源只能以串行方式访问,用于表示每个长期资源的单个线程和每个长时间运行的过程是构造代码的典型方法。 GUI只是典型程序管理的几种资源中的一种。所以“GUI程序”绝不是单线程的,但GUI库通常都是。
在琐碎的程序中,将其他程序逻辑放入GUI线程中没有明显的损失,但是当遇到大量负载或资源管理需要大量阻塞或轮询时,这种方法就会崩溃,这就是为什么你经常会看到在几乎任何GUI库的尘土飞扬的角落中提到的事件队列,信号槽消息抽象或其他多线程/处理方法(这里我包括游戏库 - 而游戏库通常期望你基本上构建你的自己的小部件围绕着你自己的UI概念,基本原理非常相似,只是有点低级别。)
[顺便说一下,我最近做了很多Qt / C ++和Wx / Erlang。 The Qt docs do a good job of explaining approaches to multi-threading,GUI循环的作用,以及Qt的信号/槽方法适合抽象(因此您不必非常考虑并发/锁定/排序/调度/等)。 Erlang本质上是并发的,但是wx itself is typically started as a single OS process that manages a GUI update loop和Erlang将事件更新为消息,并且GUI事件作为消息发送到Erlang端 - 从而允许正常的Erlang并发编码,但提供单点GUI事件排序这样wx可以做GUI更新循环的事情。]