为什么我应该使用线程而不是进程?

59
将程序的不同部分分离到不同的进程中,似乎比将所有东西都线程化更加优雅。在什么情况下,使用线程运行事物与将程序分离为不同的进程才有意义?何时应该使用线程?单核和多核操作是否会影响它们的表现方式?
8个回答

92

您希望使用多个线程而不是多个进程的原因有两个:

  1. 在线程之间进行通信(共享数据等)比进程间通信简单得多。
  2. 在线程之间进行上下文切换比在进程之间进行上下文切换更快。也就是说,操作系统停止一个线程并开始运行另一个线程的速度比停止一个进程并开始运行另一个进程的速度更快。

例如:

具有图形用户界面(GUI)的应用程序通常将一个线程用于GUI,其他线程用于后台计算。例如,MS Office中的拼写检查器是一个与运行Office用户界面的线程分离的线程。在这种应用程序中,使用多个进程而不是多个线程会导致性能变慢,并且代码难以编写和维护。


9
数据共享是一枚双面硬币,然而。你可以轻易地弄乱另一个线程的数据... - Thilo
2
速度优势是否也适用于多核?典型的操作系统通常是否允许这样做? - danmine
3
通常情况下,你不应该试图预测操作系统的调度行为。你无法确定你的线程是否会在单独的核心上运行或者在同一个核心上运行。对于多个进程也是如此。因此,不要依赖于多核处理器。 - Frederick The Fool
1
虽然你说的一般都是对的,但在某些情况下你可以确定线程将在哪些核心上运行,因为(至少在Windows上)你可以设置处理器亲和性掩码。这在计时目的下很有用,因为更改核心可能会导致跳跃或(更糟糕的是)时间倒流。 - OregonGhost
4
“多线程对于‘初学者’来说可能很危险。” 你的意思比你想象的更正确!我相信你的意思是“‘未’受过训练的”,但对于受过训练的人来说,它也是危险的。 - Bryan Oakley
显示剩余2条评论

40

除了使用线程而不是进程的优点外,还有:

优点:

  • 创建线程比创建进程快得多。
  • 在线程之间切换比在进程之间切换要快得多。
  • 线程可以轻松共享数据。

但也需要考虑一些缺点:

  • 线程之间没有安全性保障。
  • 一个线程可以覆盖另一个线程的数据。
  • 如果一个线程被阻塞,任务中的所有线程都会被阻塞。

至于你问题中重要的部分“何时应该使用线程?”

那么你应该考虑到一些事实,即线程不应改变程序的语义。它们只是改变操作的时间。因此,它们几乎总是用作性能相关问题的简洁解决方案。以下是一些可能使用线程的情况的示例:

  • 进行长时间处理:当 Windows 应用程序在计算时,无法处理任何更多的消息。结果,显示器无法更新。
  • 进行后台处理:某些任务可能不是时间关键型的,但需要持续执行。
  • 进行 I/O 工作:磁盘或网络 I/O 可能具有不可预测的延迟。线程允许您确保 I/O 延迟不会延迟应用程序的其他部分。

10
当一个线程阻塞时,你确定所有线程都会被阻塞吗?你所谓的“阻塞”是什么意思?是指等待 I/O 被阻塞吗?你使用的是哪种类型的线程?我知道 PThreads 不会阻塞。 - Stephen Curial
4
像阻塞等待资源这样的情况,很多人都讨厌。因为线程没有自己的地址空间,所以它们并不是隔离的。如果一个线程出错,可能会影响整个进程或程序,导致整个内存空间中所有线程的使用受到影响。请注意阻塞! - simplyharsh
感谢您指出这些缺点。 - seokhoonlee
支持 @simplyharsh 的观点。考虑当同一进程的线程死锁时,你的进程就像已经死亡了一样。 - pcodex

7

我假设你已经知道需要使用线程或进程,所以我认为选择其中一个的主要原因是数据共享。

使用进程意味着您还需要进行进程间通信(IPC)来将数据输入和输出进程。如果该进程需要隔离,则这是一件好事。


我喜欢进程隔离方面的特点。 - danmine

7
你听起来一点也不像新手。这是一个很好的观察,进程在许多方面更加优雅。线程基本上是为了避免过多的转换或内存空间之间的通信而进行的优化。
表面上使用线程似乎也使得程序更易于阅读和编写,因为你可以自由地在线程之间共享变量和内存。实际上,这需要非常仔细地注意,以避免竞争条件或死锁。
有一些操作系统内核(最著名的是 L4)试图尽力提高进程间通信的效率。对于这样的系统,人们可能会认为线程是毫无意义的。

7
我想用不同的方式来回答这个问题。我的回答是“取决于您的应用程序的工作场景和性能SLA”。例如,线程可能共享相同的地址空间,并且线程之间的通信可能更快、更容易,但在某些条件下,线程可能会死锁,那么您的进程将会发生什么情况呢?即使您是一个编程高手,并已使用了所有花哨的线程同步机制来防止死锁,也可以很容易地看出,除非遵循一种确定性模型,这可能是硬实时系统运行在真实时间操作系统上的情况,您对线程优先级具有一定程度的控制,并且可以期望操作系统尊重这些优先级,否则,对于像Windows这样的通用目的操作系统来说,情况可能并非如此。从设计角度来看,您可能希望将功能隔离到独立的自包含模块中,在这种情况下,它们可能不需要共享相同的地址空间或内存,甚至不需要彼此交流。这是进程有意义的情况。以Google Chrome为例,与大多数使用多线程模型的浏览器不同,Chrome会生成多个进程。Chrome中的每个标签都可以与不同的服务器通信并呈现不同的网站。想象一下,如果一个网站停止响应,如果您有一个由于此而停滞不前的线程,整个浏览器要么变慢,要么停止工作。因此,Google决定生成多个进程,这就是为什么即使一个选项卡冻结,您仍然可以继续使用Chrome浏览器的其他选项卡的原因。了解更多信息,请单击此处此处

3

我同意上面大部分的回答。但是从设计角度来看,当我想要一组逻辑相关的操作并行执行时,我宁愿选择线程。例如,如果您运行一个文字处理器,将有一个线程在前台作为编辑器运行,另一个线程在后台定期自动保存文档,因此没有人会单独设计一个过程来执行该自动保存任务。


2
除了其他答案之外,维护和部署单个进程比拥有多个可执行文件要简单得多。
使用多个进程/可执行文件来提供明确定义的接口/解耦,以便其中一部分可以比在一个进程中保留所有功能更容易地被重用或重新实现。

0

看到这篇文章,讨论很有趣。但我觉得缺少了一个点或者是间接指出了。

创建新进程是昂贵的,因为必须分配和初始化所有数据结构。将进程细分为不同的控制线程以实现进程内多线程。

使用线程或进程来实现目标取决于您的程序使用要求和资源利用率。


2
我可能错了,但我认为在Unix系统中,fork命令会复制一个进程而不会复制其地址空间(直到其中一个进程写入它,然后只复制被写入的部分),因此它并不那么昂贵。 - frankelot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接