何时多线程不是一个好主意?

时间:2008-09-18 15:54:28

标签: multithreading language-agnostic

我最近正致力于通过以太网和串口发送和接收消息的应用程序。然后,我被委托添加监控DIO离散度。我经常,

  

“没理由打断主力   消息中涉及的线程   处理,我只是创建   监控DIO的 另一个线程 。“

然而,这个决定被证明是。有时,主线程将在发送和接收串行消息之间中断。这种中断会破坏时间,唉,消息会永远丢失。

我发现了另一种监控DIO 而不使用其他线程的方法,并且以太网和串行通信恢复了正常的功能。

然而,整个惨败让我思考。 关于何时使用多线程的任何一般指导和/或任何人在使用多线程时是否还有其他情况的例子都不是一个好主意?

**编辑:根据您的意见,在搜索互联网获取信息后,我撰写了一篇名为When is multi-threading not a good idea?的博客文章

14 个答案:

答案 0 :(得分:13)

  1. 在单处理器计算机和桌面应用程序上,您使用多线程,因此您不会冻结应用程序,而是真正的其他任何内容。
  2. 在单处理器服务器和基于Web的应用程序上,不需要多线程,因为Web服务器处理大部分内容。
  3. 在多处理器计算机和桌面应用程序上,建议您使用多线程和并行编程。制作与处理器一样多的线程。
  4. 在多处理器服务器和基于Web的应用程序上,不再需要多线程,因为Web服务器会处理它。
  5. 总的来说,如果您使用多个线程而非冻结桌面应用程序以及任何其他通用答案,那么由于线程中断,您将使应用程序更慢如果您拥有单个核心计算机彼此。

    为什么呢?因为硬件开关。硬件总是在线程之间切换需要时间。在一个多核盒子上,继续为每个核心使用1个线程,你会看到一个提升。

答案 1 :(得分:6)

用一句旧话来解释:程序员遇到了问题。他想,“我知道,我会使用线程。”现在程序员有两个问题。 (通常归因于JWZ,但似乎早于他使用它来谈论正则表达式。)

一个好的经验法则是“不要使用线程,除非有一个非常令人信服的理由使用线程。”多线程都在寻找麻烦。尝试在不使用多个线程的情况下找到解决问题的好方法,并且只有在避免使用线程时才会回退使用线程,这与使用线程的额外工作一样麻烦。此外,如果您在多核/多CPU计算机上运行,​​请考虑切换到多个线程,单线程版本的性能测试表明您需要额外核心的性能。< / p>

答案 2 :(得分:6)

如果出现以下情况,多线程是一个坏主意:

  • 多个线程访问并更新相同的资源(设置变量,写入文件),但您不理解thread safety

  • 多个线程互相交互,您不了解mutexes和类似的线程管理工具。

  • 您的程序使用静态变量(默认情况下,线程通常会共享它们)。

  • 您尚未调试并发问题。

答案 3 :(得分:4)

实际上,多线程不可扩展且难以调试,因此如果您可以避免它,则不应该在任何情况下使用它。在很少的情况下强制要求:当多CPU上的性能很重要时,或者当你处理有很多客户需要很长时间才能回答的服务器时。

在任何其他情况下,您可以使用队列+ cron作业等替代方案。

答案 4 :(得分:3)

您可能需要查看Dan Kegel关于处理多个数据源/接收器的“The C10K problem”网页。

基本上最好使用最小线程,套接字可以在大多数操作系统中使用某些事件系统(或在Windows中使用IOCP异步)。

当您遇到操作系统和/或库不提供以非阻塞方式执行通信的方式时,最好使用线程池来处理它们,同时向同一事件报告循环。

布局示例图:

Per CPU [*] EVENTLOOP   ------ Handles nonblocking I/O using OS/library utilities
                       |                        \___  Threadpool for various blocking events
                       Threadpool for handling the I/O messages that would take long

答案 5 :(得分:2)

如果您需要保证精确的物理时序(如您的示例中),则多线程不是一个好主意。其他缺点包括线程之间的密集数据交换。我会说如果你不太关心它们的相对速度/优先级/时间,那么多线程对于真正的并行任务是有好处的。

答案 6 :(得分:2)

我写的最近的一个应用程序 使用多线程(尽管不是无限数量的线程)是我必须通过两个协议在多个方向上进行通信,以及监视第三个资源以进行更改的应用程序。两个协议库都需要一个线程来运行相应的事件循环,当考虑到这些时,很容易为资源监视创建第三个循环。除了事件循环要求之外,通过线路的消息具有严格的时序要求,并且一个环路不会有风险阻塞另一个环路,这可以通过使用多核CPU(SPARC)进一步减轻。

有进一步讨论是否应将每个消息处理视为从线程池中给予线程的作业,但最后这是一个不值得工作的扩展。

总而言之,只有在可以将工作分区为明确定义的作业(或一系列作业)时,才应考虑线程,以便语义相对容易记录和实现,并且可以放置一个上层绑定您使用的线程数和需要交互的线程数。最适用的系统几乎是消息传递系统。

答案 7 :(得分:2)

多线程很糟糕,除非它是好的单一情况。这个案例是

  1. 工作是CPU绑定,或部分是CPU绑定
  2. 这项工作是可以并行的。
  3. 如果缺少这些条件中的任何一个或两个,多线程就不会成为一个成功的策略。

    如果工作不受CPU限制,那么您不是在等待线程完成工作,而是等待某些外部事件(例如网络活动),以便流程完成其工作。使用线程,线程之间的上下文切换的额外成本,同步的成本(互斥等)以及线程抢占的不规则性。最常见的替代方案是异步IO,其中单个线程侦听多个io端口,并且对现在准备就绪的任何一个进行操作,一次一个。如果有可能这些慢速通道都在同一时间准备就绪,看起来你可能会遇到减速,但实际上这很少是真的。单独处理每个端口的成本通常与每个通道清空时在多个线程上同步状态的成本相当或更好。

    许多任务可能是计算绑定的,但使用多线程方法仍然不实际,因为进程必须在整个状态上同步。这样的程序不能从多线程中受益,因为不能同时执行任何工作。幸运的是,大多数需要大量CPU的程序可以并行化到某种程度。

答案 8 :(得分:1)

原则上,每次调用者没有开销在队列中等待的开销。

答案 9 :(得分:1)

我想说多线程通常用于:

  1. 在GUI保持响应时允许在后台进行数据处理
  2. 将非常大的数据分析拆分到多个处理单元,以便您可以更快地获得结果。
  3. 当您从某些硬件接收数据并需要继续将其添加到缓冲区时,而其他一些元素决定如何处理它(写入磁盘,在GUI上显示等)。
  4. 因此,如果您没有解决其中一个问题,那么添加线程不太可能让您的生活更轻松。事实上,它几乎肯定会变得更难,因为正如其他人所提到的那样;调试mutithreaded应用程序比单线程解决方案要多得多。

    安全性可能是避免使用多个线程(多个进程)的原因。有关多进程安全功能的示例,请参阅Google chrome

答案 10 :(得分:1)

使用线程的几个可能的原因:

  1. 您的平台缺少异步I / O操作,例如Windows ME(没有完成端口或重叠的I / O,在移植使用它们的XP应用程序时很痛苦。)Java 1.3及更早版本。
  2. 可以挂起的第三方库函数,例如如果远程服务器已关闭,并且库无法取消该操作,则无法对其进行修改。
  3. 在密集处理期间保持GUI响应并不总是需要额外的线程。单个回调函数通常就足够了。

    如果以上都不适用,我仍然希望出于某种原因并行,我希望尽可能启动一个独立的过程。

答案 11 :(得分:0)

流程是否平行?性能真的是一个问题吗?在Web服务器上是否存在多个“执行线程”?我认为没有一个有限的答案。

答案 12 :(得分:0)

线程问题的常见来源是用于同步数据的常用方法。让线程共享状态然后在所有适当的位置实现锁定是设计和调试的主要复杂因素。获得正确的锁定以平衡稳定性,性能和可扩展性始终是一个难以解决的问题。即使是经验最丰富的专家也经常弄错。处理线程的替代技术可以减轻这种复杂性。 Clojure编程语言实现了几种处理并发的有趣技术。

答案 13 :(得分:0)

多线程是可扩展的,并且允许您的UI在后台执行非常复杂的操作时保持其响应性。我不明白其他回复在哪里获取有关多线程的信息。

当你不应该多线程是一个错误的问题你的问题。您的问题是:为什么我的应用程序多线程导致串行/以太网通信失败?

该问题的答案将取决于实施,应在另一个问题中讨论。我知道您可以在多线程应用程序中同时执行以太网和串行通信,同时执行许多其他任务,而不会导致任何数据丢失。

不使用多线程的一个原因是:

  1. 有一个任务,没有用户界面与任务干扰。
  2. 使用多线程的原因是:

    1. 为用户提供卓越的响应能力
    2. 同时执行多项任务以减少总体执行时间
    3. 使用更多当前的多核CPU和未来的多核。
    4. 多线程编程有三种基本方法可以轻松实现线程安全 - 您只需使用一个即可获得成功:

      1. 线程之间传递的线程安全数据类型。
      2. 线程安全方法在线程对象中修改之间传递的数据。
      3. PostMessage在线程之间进行通信的功能。