User interface 关于GUI应用程序中线程数量的最佳实践

User interface 关于GUI应用程序中线程数量的最佳实践,user-interface,language-agnostic,User Interface,Language Agnostic,在过去,我与许多专门编写GUI应用程序的程序员一起工作 我得到的印象是,他们在应用程序中几乎普遍减少了多线程的使用。在某些情况下,他们似乎已经走到了极端长度,以确保他们使用一个单一的线程 这是常见的吗?这是公认的gui应用程序设计理念吗 如果是,为什么 [编辑] 有许多答案认为线程的使用应该最小化以降低复杂性。总体而言,降低复杂性是一件好事 但是,如果您查看对外部事件的响应至关重要的任意数量的应用程序(例如web服务器、任意数量的嵌入式应用程序)对线程使用的态度似乎有着天壤之别。我认为在wind

在过去,我与许多专门编写GUI应用程序的程序员一起工作

我得到的印象是,他们在应用程序中几乎普遍减少了多线程的使用。在某些情况下,他们似乎已经走到了极端长度,以确保他们使用一个单一的线程

这是常见的吗?这是公认的gui应用程序设计理念吗

如果是,为什么

[编辑]

有许多答案认为线程的使用应该最小化以降低复杂性。总体而言,降低复杂性是一件好事


但是,如果您查看对外部事件的响应至关重要的任意数量的应用程序(例如web服务器、任意数量的嵌入式应用程序)对线程使用的态度似乎有着天壤之别。

我认为在windows中,您仅限于在单个线程上执行所有GUI操作-因为windows消息泵的工作方式,为了提高响应性,大多数应用程序至少会为运行时间较长的任务添加一个额外的工作线程,否则会阻塞ui并使其无响应


线程从根本上说是很难的,因此从一个或多个线程的角度进行思考通常会导致大量的调试工作-我现在想不起这样一句话——“如果你认为你理解线程,那么你真的不理解”

GUI通常不会使用大量的线程,但是他们经常会为与某些子系统的交互抛出另一条线索,特别是当这些系统需要一段时间或者是非常共享的资源时

例如,如果您要打印,您通常需要中断另一个线程来与打印机池交互,因为打印机池可能会很忙一段时间,并且没有理由不继续工作


另一个例子是与SQL server或类似工具交互时的数据库加载,由于延迟,您可能需要创建另一个线程,以便主UI处理线程可以继续响应命令。

大多数GUI框架都不是线程安全的,这意味着我必须从创建控件的同一线程访问所有控件。尽管如此,创建工作线程以使应用程序具有响应性仍然是一个很好的做法,但是您需要小心地将GUI更新委托给GUI线程。

应用程序中的线程越多,(通常)解决方案越复杂。通过尽量减少GUI中使用的线程数量,出现问题的潜在区域就更少了

另一个问题是GUI设计中最大的问题:人。人类因不能同时做多种事情而臭名昭著。用户习惯于快速点击多个按钮/控件,以便更快地完成任务。计算机通常无法跟上这一点(这仅由GUI通过使用多个线程来跟上的明显能力构成),因此为了最小化这种影响,GUI将在单个线程上以先到先得的方式响应输入。通过这样做,GUI被迫等待系统资源空闲,直到可以继续。因此,消除所有可能出现的令人讨厌的死锁情况。显然,如果程序逻辑和GUI在不同的线程上,那么这就不存在了


出于个人偏好,我更喜欢在一个线程上保持简单,但不损害GUI的响应性。如果一项任务花费的时间太长,那么我将使用不同的线程,否则我将只使用一个线程。

我也看到了同样的情况。理想情况下,您应该在后台线程中执行比几百毫秒更长的任何操作。任何超过100毫秒的分拣机和人类可能都不会注意到这一差异

我过去和很多GUI程序员一起工作过,他们害怕线程,因为线程“很难”。在一些GUI框架(如Delphi VCL)中,存在关于从多个线程使用VCL的警告,这往往会吓到一些人(其他人将其视为一种挑战;)


多线程GUI编码的一个有趣示例是BEOSAPI。应用程序中的每个窗口都有自己的线程。根据我的经验,这让BeOS应用程序感觉更灵敏,但它确实让编程变得更棘手。幸运的是,由于BeOS在默认情况下被设计为多线程的,因此API中有很多东西比我使用的其他一些操作系统更简单。

一般来说,GUI框架不是线程安全的。对于像Swing(Java的GUI API)这样的东西,只有一个线程可以更新UI(否则会发生不好的事情)。只有一个线程处理调度事件。如果有多个线程更新屏幕,可能会出现一些难看的闪烁和错误的图形


然而,这并不意味着应用程序需要是单线程的。当然,在某些情况下,你不希望出现这种情况。如果你点击一个将pi计算为1000位数的按钮,你就不想在接下来的几天里锁定UI并按下按钮。这是像SwingWorker这样的东西派上用场的时候。它有两个部分:一个是doInBackground(),在单独的线程中运行;另一个是done(),在doInBackground线程完成后由处理更新UI的线程调用。这允许快速处理事件,或者在后台处理需要很长时间的事件,同时仍然使用单线程更新屏幕。

正如前面的评论所说,GUI框架(至少在Windows上)是单线程的,因此是单线程的。另一个建议(在实践中很难编码)是将线程数量限制为机器上可用的内核数量。您的CPU只能执行一个操作