Answers:
您的1,805个线程不会同时运行。他们权衡。一个内核运行一部分线程,然后将其放在一边以执行另一线程。其他核心也一样。一遍又一遍,线程一次执行一点,而不是一次执行。
操作系统(Darwin和macOS)的主要职责是调度在哪个内核上执行哪个线程持续多长时间。
许多线程没有工作要做,因此处于休眠状态且未计划。同样,许多线程可能正在等待某些资源,例如要从存储中检索的数据,要完成的网络连接或要从数据库加载的数据。除了检查等待资源的状态外,几乎不需要执行任何操作,因此对这些线程进行了很短的调度(如果有的话)。
当应用程序程序员知道等待外部资源将花费一些时间时,可以通过将其线程休眠一定时间来协助此调度操作。而且,如果运行CPU密集型的“紧密”循环而没有理由等待外部资源,则程序员可以插入一个调用以自愿将其暂时搁置,以免占用内核,从而允许其他线程执行。
有关更多详细信息,请参见Wikipedia页面上的多线程。
至于您链接的Question,线程确实与此处相同。
一个问题是,由操作系统调度时在线程之间切换会产生开销。从内核中卸载当前线程的指令和数据,然后加载下一个调度线程的指令和数据会花费大量的时间。操作系统的一部分工作是尝试明智地调度线程,以优化此开销成本。
一些CPU制造商已经开发出可以缩短时间的技术,从而可以更快地在一对线程之间进行切换。英特尔称其技术为“超线程”。通常称为同时多线程(SMT)。
尽管这对线程实际上并没有同时执行,但切换是如此平稳和快速,以至于两个线程实际上是同时执行的。这样效果很好,每个内核都将自己呈现为OS的一对虚拟内核。因此,具有四个物理核心的启用SMT的CPU将作为八核CPU展示给操作系统。
尽管进行了优化,但在这些虚拟内核之间进行切换仍然存在一些开销。太多的CPU密集型线程都要求在内核上安排执行时间,这会使系统效率低下,而没有一个线程可以完成很多工作。就像操场上的三个球在9个孩子之间共享,而在900 个孩子之间共享时,没有一个孩子真正得到任何严肃的游戏时间。
因此,CPU固件中有一个选项,如果系统管理员认为它可以使运行非常规CPU限制的应用程序的用户受益,并且暂停的机会很少,则系统管理员可以在计算机上禁用SMT。
在这种情况下,我们会回到您原来的问题:在这种特殊情况下,您确实希望限制操作,使这些超活动线程不超过物理内核。但是,我再重复一遍:这是一种非常不寻常的情况,它可能发生在类似专门的科学数据处理项目中,但几乎永远不会应用于常见的业务/公司/企业场景。
yield()
系统调用放入其CPU密集型线程中(除非它是Classic MacOS上协作多任务处理的遗留代码)。线程用完其时间片后,抢先式多任务重新安排。
在过去,内存没有被虚拟化或保护,任何代码都可以写在任何地方。在那些日子里,一个线程到一个CPU设计是有意义的。从那以后的几十年中,内存首先受到保护,然后进行虚拟化。将线程视为虚拟核心-这是一种承诺,即在您的数据和代码准备好后的某个时间,该线程会被推送(或按进行调度算法研究的PHD工程师和数学家称之为的方式调度)到实际的CPU上,做实际的工作。
现在-由于时序上的差异-与从存储或网络获取数据相比,CPU和缓存的运行速度如此之快-数以千计的线程可以来去去,而一个线程正在等待www.google.com提供一两个数据包,这就是为什么看到的线程比实际CPU多得多的原因。
如果将在黑色/蓝色时间范围内发生的线程操作转换为1秒= 1 ns,我们关心的事情就更像是磁盘IO需要100微秒,就像4天,而200毫秒的互联网往返就是如果要计算CPU时间范围的秒数,则延迟20年。就像十次练习的许多功能一样,几乎在所有情况下-CPU都处于空闲状态数月,以等待非常非常慢的外部环境中有意义的工作。
在您发布的图像中似乎没有什么不妥,因此也许我们对线程感到疑惑而误解了您所得到的。
如果在顶部标题行中的单词线程上单击鼠标右键(控制单击),请添加应用程序的状态,您将看到大多数线程在任何给定的时间可能都处于空闲,休眠状态。
您不会问一个更基本的问题:“当我的CPU只有四个内核时,我怎么能拥有290个进程?” 这个答案有一段历史,即使已经回答了特定的问题,也可能有助于您了解全局。因此,我不会提供TL; DR版本。
从前(例如1950年代至60年代),计算机一次只能做一件事。它们非常昂贵,整个房间都满了,我们需要一种方法,通过在多人之间共享它们来有效利用它们。第一种方法是批处理,即用户将任务提交到计算机,然后将他们排队,一个接一个地执行,然后将结果发送回用户。没关系,但这确实意味着,如果您要进行需要几天的计算,那么在此期间没有其他人可以使用计算机。
下一个创新(认为是1960年代至70年代)是分时的。现在,计算机将执行一部分任务,然后暂停执行下一部分任务,以此类推,而不是先执行全部任务,再执行全部任务。因此,计算机给人的印象是它正在同时执行多个进程。这样做的最大好处是,您现在可以运行需要几天的计算,尽管现在甚至需要更长的时间,但由于它不断被打断,因此其他人仍可以在这段时间内使用计算机。
所有这些都是针对大型主机式计算机的。当个人计算机开始流行时,它们最初并不十分强大,但是,嘿,由于它们是个人计算机,因此他们只能一次完成一件事情,只能运行一个应用程序,这似乎是可以的(想想,1980年代)。但是,随着功能的增强(想想1990年代至今),人们也希望分时使用他们的个人计算机。
因此,我们最终使用了个人计算机,通过在短时间内一次实际运行多个进程然后暂停它们,从而产生了同时运行多个进程的幻觉。线程本质上是同一件事:最终,人们甚至想要单个进程来产生同时做多个事情的错觉。首先,应用程序编写者必须自己处理:花一些时间来更新图形,暂停一下,花点时间进行计算,暂停一下,花点时间来做其他事情,...
但是,操作系统已经擅长管理多个进程,因此有必要将其扩展为管理这些称为线程的子进程。因此,现在,我们有了一个模型,其中每个进程(或应用程序)至少包含一个线程,而有些包含多个线程。这些线程中的每个线程都对应一个稍微独立的子任务。
但是,在最高级别,CPU仍然只是给人一种幻想,即这些线程都同时运行。实际上,它正在运行一小段时间,暂停它,选择另一个运行一小段时间,依此类推。除了现代的CPU可以一次运行多个线程外。所以,在真正的现实,操作系统同时玩这个游戏“了一下,暂停运行,运行其他的东西了一会儿,暂停”对所有核心。因此,您可以根据需要(和您的应用程序设计人员)拥有尽可能多的线程,但是在任何时候,除少数线程外,其他线程实际上都会被暂停。