【问题标题】:What is the relationship between number of CPU cores and number of threads in an app in java?java中应用程序中的CPU内核数和线程数之间有什么关系?
【发布时间】:2014-02-05 03:30:49
【问题描述】:

我是 java 多线程 编程的新手。我想到的问题是,根据我的 CPU 内核 的数量,我可以运行多少线程。如果我运行的线程多于 CPU 内核,那么机器运行应用程序是否会产生开销。例如,当我们有一台服务器机器,它的服务器软件运行 2 个线程(主线程 + 开发人员线程)时,当更多的同时客户端与服务器建立套接字连接时,服务器是否会产生开销?

谢谢。

【问题讨论】:

    标签: java multithreading sockets networking


    【解决方案1】:

    不必有任何关系。一台计算机可以有任意数量的内核;一个进程可以有任意数量的线程。

    进程使用线程有几个不同的原因,包括:

    • 编程抽象。划分工作并将每个部分分配给一个执行单元(线程)是解决许多问题的自然方法。使用这种方法的编程模式包括反应器、每个连接的线程和线程池模式。然而,有些人将线程视为一种反模式。无与伦比的 Alan Cox 用一句话很好地总结了这一点,“线程是为不会编程状态机的人准备的。”

    • 阻塞 I/O。如果没有线程,阻塞 I/O 会停止整个进程。这可能对吞吐量和延迟都有害。在多线程进程中,单个线程可能会阻塞,等待 I/O,而其他线程会向前推进。因此,通过线程阻塞 I/O 是异步和非阻塞 I/O 的替代方案。

    • 节省内存。线程提供了一种有效的方式来共享内存,同时利用多个执行单元。通过这种方式,它们可以替代多个进程。

    • 并行性。在具有多个处理器的机器中,线程提供了一种实现真正并行性的有效方法。由于每个线程都有自己的虚拟化处理器,并且是一个可独立调度的实体,因此多个线程可以同时在多个处理器上运行,从而提高系统的吞吐量。就线程用于实现并行性而言——也就是说,线程数不超过处理器数——“线程是为不能编程状态机的人准备的”引用并不适用。

    前三个项目符号使用与内核无关的线程。例如,如果您使用线程作为编程抽象来处理 UI 元素,那么无论您有 1 个核心还是 12 个核心,每个 UI 元素(或其他任何东西)都将拥有一个线程。同样,如果您使用线程来执行阻塞I/O,你会根据你的 I/O 容量而不是你的处理能力来扩展你的线程数。

    但是,第四个项目符号确实将线程与内核相关联。如果线程的目标是并行性,那么线程数应该与内核数成线性关系。例如,如果您将系统中的内核数量增加一倍,那么您的应用程序中的线程数量也会增加一倍。这对于逻辑意义上的内核(即包括 SMT)来说是正确的。

    当使用线程来实现并行性时(这既是线程的常见用途,也是最佳的使用方式)通常每个内核会有一个或两个线程。通常,编写应用程序是为了根据可用内核的数量动态调整线程池的大小。每个内核单个线程是理想的,但应用程序通常使用更大的乘数,例如每个内核两个线程,这是由于代码中的错误和低效率,例如在不应该阻塞时阻塞的操作。

    【讨论】:

      【解决方案2】:

      当核心数(NOC)等于线程数(NOT)时,性能最佳,因为如果不是> NOC,那么处理器应该切换上下文 或操作系统会尝试完成这项工作,这已经足够昂贵了。但是您必须了解,在 Web 服务器上不可能有 NOC = NOT,因为您无法预测同时会有多少客户端。看看load balancing 的概念,以最好的方式解决这个问题。

      【讨论】:

      • 这是一个常见的误解。如果上下文切换如此糟糕,操作系统开发人员不会只是编写操作系统而不执行它们吗?显然,除非您的操作系统是由白痴开发的,否则上下文切换只会在有益的地方进行。因此,避免上下文切换不是减少线程数量的合理理由。您可以拥有 10 个线程并每秒执行 X 次上下文切换,或者您可以拥有 100 个线程并每秒执行相同的 X 次上下文切换。所需的上下文切换数量取决于其他设计因素。
      • 上下文切换可能曾经很昂贵,但现在肯定不会;操作系统不再是硬件的愚蠢包装器,CPU 速度很快。人们不会花时间检查他们所知道的是否仍然是最新的(“Java 很慢!”),这更多是 IMO 这类陈述的问题。
      • 我不认为java很慢,反之我认为它足够快。并且可能的操作系统会尝试避免切换上下文,并会在 SW 级别进行,但我的帖子的主要思想并没有因此而改变,而且绝对正确。
      • 当核心数 (NOC) 等于线程数 (NOT) 时性能最佳 - 奇怪,因为我的盒子 ATM 上有 1311 个线程,而且运行良好。
      • @Divers 你说的没错 - 问题是,它只适用于非常有限的场景类型:纯粹的 CPU 受限数字计算。一旦等待涉及的 I/O(或用户),当有 更多 个线程而不是内核时,CPU 的利用率会好得多,因为并非所有线程都准备好随时运行。同样,通用的“上下文切换很昂贵”声明毫无意义,它们对于将单个内核多路复用到多个任务是必要的。花一些时间进行上下文切换仍然比忙于轮询 IO 完成要好得多。
      【解决方案3】:

      它背后的想法是不要让你的 CPU 休眠,也不要加载太多,以免将大部分时间浪费在线程切换上。

      检查 Tuning the pool size, In IBMs paper 有帮助

      背后的想法是,它取决于任务的性质,如果它的所有内存计算任务都可以使用 N+1 线程(N 个核心(包括超线程))。

      或者

      我们需要进行应用程序分析并找出典型请求的等待时间 (WT) 、服务时间 (ST) 以及我们可以拥有的大约 N*(1+WT/ST) 的最佳线程数,考虑到 100% CPU 利用率。

      【讨论】:

        【解决方案4】:

        系统可以同时执行的线程数(当然)与系统中的内核数相同。

        系统上可以存在的线程数受可用内存的限制(每个线程都需要一个堆栈和操作系统用来管理线程的结构),并且可能存在操作系统允许的线程数限制(这取决于操作系统架构,一些操作系统可能会使用固定大小的表,一旦它满了就不能再创建线程了)。

        通常,今天的计算机可以处理成百上千个线程。

        系统中使用的线程多于核心的原因是:大多数线程不可避免地会花费大量时间等待某些事件(例如:文字处理器等待用户在键盘上键入)。操作系统管理它,以这种方式等待的线程不会消耗 CPU 时间。

        【讨论】:

          【解决方案5】:

          不必担心线程数比 CPU 内核数多;这实际上不在您的手中,而是在操作系统中。

          假设 JVM 将您的 java 线程映射到 OS 线程(这在当今相当正常),这取决于您的 OS 执行的线程管理。在那里,您需要依靠内核实现的智能程度来从内核中获取性能。

          您必须牢记的是,您的设计必须是可持续的。例如,应用程序服务器建立在一个充满工作线程的线程池上。这些线程被唤醒以服务请求。你想为每个请求一个线程吗?那么你肯定会遇到问题 - 请求可能以数千个形式到达服务器,这可能是内核管理的问题。实际上,线程池的大小应该是有限的(在 1 和 X 之间,并且即使实时也很容易更改),线程应该从并发队列中获取工作(java 为您提供了一些优秀的类)并且每个线程都按顺序处理请求。

          希望对你有帮助

          【讨论】:

            【解决方案6】:

            线程数少于 CPU 可能意味着您没有使用系统中的所有 CPU。如果 CPU 是您的瓶颈,拥有更多线程可能会提高吞吐量。

            拥有比 CPU 更多的线程确实会带来开销,如果 CPU 是您的瓶颈,这可能会损害性能。但是,如果网络 IO 是您的瓶颈,那么这种开销是值得付出的代价,因为它通常允许您处理更多的连接。例如你可以有 1000 个 TCP 连接,它们有自己的线程。

            【讨论】:

              【解决方案7】:

              这取决于线程在做什么。 CPU 一次只能做 X 件事,其中 X 是它拥有的内核数。这意味着 X 线程最多可以在任何时候处于活动状态 - 但是其他线程可以等待轮到它们,CPU 会在适当的时候处理它们。

              您还应该考虑到很多时间线程都在等待响应,或等待数据加载,或网络消息到达等,因此实际上并没有尝试做任何事情。这些空闲/等待线程对系统的负载很小。

              【讨论】:

              • 服务器是否在每个客户端连接的 main() 方法中创建一个自己的对象,如果这样做,服务器为每个对象运行一个额外的线程是否会产生开销(我的意思是它对网络速度的影响)?谢谢先生。
              • 我不太明白你的评论。创建了一个线程来运行main。线程只是松散地连接到网络速度。
              猜你喜欢
              • 1970-01-01
              • 2011-06-28
              • 2019-02-20
              • 2014-02-07
              • 2020-04-23
              • 1970-01-01
              • 2013-12-04
              • 2018-03-19
              • 1970-01-01
              相关资源
              最近更新 更多