【问题标题】:When is multi-threading not a good idea? [closed]什么时候多线程不是一个好主意? [关闭]
【发布时间】:2012-02-01 23:17:19
【问题描述】:

我最近正在开发一个通过以太网和串行发送和接收消息的应用程序。然后我的任务是添加 DIO 离散的监控。我通过了,

"没有理由中断主 消息中涉及的线程 处理,我将创建 另一个线程监控 DIO。”

然而,这个决定被证明是糟糕的。有时主线程会在发送和接收串行消息之间中断。这种中断会打乱时间,唉,消息会丢失(永远)。

我找到了另一种方法来监控 DIO,无需使用其他线程,以太网和串行通信已恢复到正确的功能。

然而,整个惨败让我思考。 他们是否有关于何时使用多线程的一般准则和/或是否有人再有使用多线程不是一个好主意的情况示例? p>

**编辑:根据你的cmets,在网上搜索信息后,我写了一篇题为When is multi-threading not a good idea?的博客文章

【问题讨论】:

    标签: multithreading language-agnostic


    【解决方案1】:
    1. 在单处理器机器和桌面应用程序上,您使用多线程,这样您就不会冻结应用程序,而实际上没有别的。
    2. 在单处理器服务器和基于 Web 的应用程序上,无需多线程,因为 Web 服务器处理大部分。
    3. 在多处理器机器和桌面应用程序上,建议您使用多线程和并行编程。创建与处理器一样多的线程。
    4. 在多处理器服务器和基于 Web 的应用程序上,不再需要多线程,因为 Web 服务器会处理它。

    总的来说,如果您使用多个线程而不是解冻桌面应用程序和任何其他通用答案,您将使应用程序变慢如果由于线程中断而您有一个单核机器彼此。

    为什么?因为硬件开关。硬件在线程之间切换总共需要时间。在多核机器上,继续为每个内核使用 1 个线程,您会看到大幅提升。

    【讨论】:

    • 有很多关于何时不使用多线程的示例,但这不是一个好的列表。 1)因此该应用程序不会冻结是合法的原因。 2) Web 服务器为每个请求生成 1 个线程。这并不意味着他们为您处理多线程。就像说的一样,Windows 为每个应用程序生成 1 个线程,因此它会为您处理它。 3) 3 是使用多线程的原因 4) 与 2 相同 总结完全错误。即使你有一个处理器,如果一个线程正在等待磁盘 I/O,第二个线程可以继续工作。
    【解决方案2】:

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

    一个好的经验法则是“不要使用线程,除非有非常令人信服的理由使用线程。”多个线程正在自找麻烦。尝试找到一种不使用多线程来解决问题的好方法,并且只有在避免使用线程与使用线程的额外努力一样麻烦时才回退到使用线程。此外,如果您在多核/多 CPU 机器上运行,请考虑切换到多线程,单线程版本的性能测试表明您需要额外内核的性能。

    【讨论】:

    • 啊。伟大的报价。以前从没听说过——哈。此外,很好的经验法则。
    • 引用错误。原文是关于“正则表达式”的。释义不包括更改引文的主题。
    • 就像我说的,虽然经常归因于 JWZ,但引用本身已经存在了更长的时间,并且在 JWZ 使用之前与正则表达式无关。鉴于这句话的历史,我认为它仍然是一个有效的释义。我无意声称 JWZ 是在谈论线程问题。在我看来,这句话是关于某人使用了一个很酷的工具,并试图将其应用于一系列过于广泛的问题,并创造了比他们解决的更多的挑战。
    【解决方案3】:

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

    • 多个线程访问和更新同一个资源(设置变量,写入文件),而你不懂thread safety

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

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

    • 您尚未调试并发问题。

    【讨论】:

    • 我认为可以肯定地说,如果您不知道如何进行多线程处理,那么对您的应用程序进行多线程处理不是一个好主意。
    • @Kieveli:一个合理的说法。使用相同的逻辑,人们可能会得出这样的结论:如果您不了解异性,那么约会也不是一个好主意……会产生类似的后果。 :-)
    【解决方案4】:

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

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

    【讨论】:

    • 为什么多线程不可扩展?哪些类型的东西使它“难以调试”?
    • 从哪里可以获得有关“队列”和“Cron”作业的更多信息?
    • 这是一条捷径。超级计算机确实证明了您可以在本地级别进行多线程扩展,但是对于 Web 应用程序,使用多个单独的小型服务器总是比使用带有线程的大型服务器获得更好的结果。由于共享资源和同步方法,很难调试。
    • 队列 + cron 在实时不是问题时使用。您的代码除了在数据库中记录操作之外不执行任何操作,并且 cron 作业弹出此队列,调用适当的脚本来完成工作,并使用操作系统的多任务处理功能而不是让您做脏活。简单方便。
    • “多线程”是绝对可扩展的。很明显,当尝试在任何时候执行的线程数量大于机器中硬件上下文的数量时,您将开始获得更少的性能优势,但这个概念本身是无限可扩展的。
    【解决方案5】:

    您可能想查看 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
    

    【讨论】:

      【解决方案6】:

      多线程是不好的,除了在单一情况下它是好的。这个案例是

      1. 工作受 CPU 限制,或部分工作受 CPU 限制
      2. 工作是可并行的。

      如果缺少这两个条件中的一个或两个,多线程将不会是一个成功的策略。

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

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

      【讨论】:

        【解决方案7】:

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

        【讨论】:

        • 有趣。这是你在某处读到的东西吗?还是您通过自己的工作发现的?
        • 我并没有真正使用物理计时,但除此之外 - 我的经验。
        【解决方案8】:

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

        关于是否应将每个消息处理视为从线程池中分配给线程的工作进行了进一步讨论,但最终这是一个不值得工作的扩展。

        总而言之,如果可能,仅当您可以将工作划分为定义明确的作业(或一系列作业)时才应考虑线程,这样语义相对容易记录和实现,并且您可以设置一个上受限于您使用的线程数和需要交互的线程数。最佳应用的系统几乎是消息传递系统。

        【讨论】:

        • 哦,对于上面的应用程序,您实际上使用了多核计算机和多核编程来阻止线程相互中断?这就是我出错的地方。你的经历很有见地。感谢分享。
        【解决方案9】:

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

        【讨论】:

        • 您能否详细说明您的答案?
        • 好吧,正如我所见,多线程是一个“坏”。所以除非你有一个优先的工作,比如 UI 中的主线程,或者当很多请求比如 web 服务器上的线程不能在一个队列中执行时,那么不要使用它们。如果呼叫者可以在一个队列中等待,那么这是首选方式。
        【解决方案10】:

        更多使用线程的可能原因:

        1. 您的平台缺少异步 I/O 操作,例如Windows ME(没有完成端口或重叠 I/O,移植使用它们的 XP 应用程序时会很痛苦。)Java 1.3 及更早版本。
        2. 可以挂起的第三方库函数,例如如果远程服务器已关闭,并且库无法取消操作并且您无法修改它。

        在密集处理期间保持 GUI 响应并不总是需要额外的线程。一个回调函数通常就足够了。

        如果以上都不适用,并且出于某种原因我仍然想要并行性,我更愿意在可能的情况下启动一个独立的进程。

        【讨论】:

          【解决方案11】:

          我会说多线程通常用于:

          1. 允许在后台处理数据,同时 GUI 保持响应状态
          2. 将超大数据分析拆分到多个处理单元,以便您更快获得结果。
          3. 当您从某些硬件接收数据并需要将其持续添加到缓冲区时,而其他一些元素决定如何处理它(写入磁盘、在 GUI 上显示等)。

          因此,如果您没有解决其中一个问题,那么添加线程不太可能让您的生活更轻松。事实上,这几乎肯定会让事情变得更难,因为正如其他人所提到的那样;调试多线程应用程序比单线程解决方案要多得多。

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

          【讨论】:

          • Chrome 反应不好。他们使用多进程来保证安全。多线程根本不提供安全性。
          • 啊。多进程。这是一个关键的区别。
          • 好点马特 - 我会修改我的帖子。
          【解决方案12】:

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

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

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

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

          1. 只有一项任务,并且该任务不会干扰用户界面。

          使用多线程的原因是:

          1. 为用户提供卓越的响应能力
          2. 同时执行多个任务以减少总体执行时间
          3. 使用更多当前的多核 CPU,以及未来的多核。

          多线程编程的三种基本方法可以轻松实现线程安全——您只需要使用一种即可成功:

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

          【讨论】:

            【解决方案13】:

            进程是否并行?性能是一个真正的问题吗?是否像在 Web 服务器上一样有多个执行“线程”?我不认为有一个有限的答案。

            【讨论】:

            • 我不一定要寻找明确的有限答案。我只是在寻找尽可能多的不同意见。
            【解决方案14】:

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-07-13
              • 1970-01-01
              相关资源
              最近更新 更多