如果例程涉及用户空间线程,阻塞操作是否会导致整个线程的上下文切换



如果这个问题太愚蠢,我道歉。我正在阅读程序的细节。根据那个页面,它说的是Goroutines are multiplexed onto a small number of OS threads, rather than a 1:1 mapping,根据我有限的知识,我能想到的是,有有限数量的操作系统线程生成,在其中,它可能使用用户空间线程或协程。这是正确的吗?如果是这样,如果我可以举个例子,如果一个程序克隆4个操作系统线程,其中有多个用户空间线程,并且碰巧在这4个线程中有一个阻塞操作以及非阻塞操作,操作系统调度器会上下文切换所有这些线程吗,因为用户空间线程对操作系统线程不透明?

出于好奇,有没有可能的C实现程序,这可以帮助理解内部?

阅读完Go in Action

后,我的理解如下

程序运行在所谓的"逻辑处理器"(不是物理处理器)中。每个逻辑处理器都绑定到一个操作系统线程。

Go 1.5之后,逻辑处理器的数量等于可用的物理处理器的数量。

Go调度器智能地在每个逻辑处理器上调度多个例程的运行

粗图如下:-

操作系统线程------逻辑处理器------程序1,程序2.....Goroutine n

现在,很可能其中一个goroutine进行阻塞系统调用。当发生这种情况时,

  1. 操作系统线程和阻塞调用的进程是与逻辑处理器分离

  2. 这个逻辑处理器现在没有OS线程。
  3. Go调度器创建一个新的OS线程,并将其附加到逻辑处理器。

  4. 已分离的线程程序和它所关联的操作系统线程继续阻塞,等待系统调用返回。

  5. 当系统调用返回时,该例程被重新附加到其中一个逻辑处理器,并被放置在其运行队列中。

  6. 操作系统线程被"搁置以备将来使用"。我猜它被添加到某种线程池。

如果程序发出一个网络I/O调用,它将以稍微不同的方式处理。

程序将从逻辑处理器中分离出来,并移动到集成的网络轮询器中。一旦轮询器说I/O操作准备好了,程序就会重新连接到逻辑处理器来处理它。

——现在,回答你的问题:-)

我不是专家,但基于以上所述,这是我认为将会发生的事情。

由于4个OS线程中的每个线程上都有一个线程程进行了阻塞系统调用,因此所有4个线程都将从它们的逻辑处理器中分离出来,并且将继续阻塞,直到系统调用返回。这4个操作系统线程将与进行阻塞系统调用的各自的例程相关联。

现在,这导致4个逻辑处理器(以及附加到它们的非阻塞例程)没有任何操作系统线程。

因此,GO调度器创建4个新的OS线程,并为这些线程分配逻辑处理器。

,

从操作系统的角度来看,4个阻塞调用的操作系统线程显然不能占用CPU时间,因为它们没有做任何事情。

所以它会将它们的上下文切换为它选择的其他非阻塞线程

最新更新