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

时间:2016-09-25 09:40:05

标签: multithreading go pthreads coroutine goroutine

如果这个问题太愚蠢,请道歉。我正在阅读goroutines Here的详细信息。根据那个页面,它说Goroutines are multiplexed onto a small number of OS threads, rather than a 1:1 mapping,我用我有限的知识可以想到的是,产生的OS线程数量有限,其中可能使用用户空间线程或协同程序。它是否正确?如果是这样,如果我可以举一个例子,如果一个程序克隆4个OS线程,其中有多个用户空间线程,并且在所有这4个线程中发生了单个阻塞操作以及非阻塞操作,那么操作系统scheduler context-switch所有这些线程,因为用户空间线程对OS线程不透明?

出于好奇,是否有可能实现goroutines的C实现,这有助于理解内部结构?

1 个答案:

答案 0 :(得分:3)

以下是我在阅读Go in Action

后理解的内容

Goroutines在所谓的“逻辑处理器”(非物理处理器)内运行。每个逻辑处理器都绑定到一个OS线程。

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

Go调度程序智能地安排在每个逻辑处理器上运行多个goroutine

粗略图如下: -

OS线程------逻辑处理器------ Goroutine 1,Goroutine 2 ..... Goroutine n

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

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

    此逻辑处理器现在没有操作系统线程。

  2. Go调度程序创建一个新的OS线程,并将其附加到逻辑处理器。附加到逻辑处理器的其余goroutine现在继续运行。

  3. 分离的goroutine和与之关联的OS线程继续阻塞,等待系统调用返回。

  4. 当系统调用返回时,goroutine会重新连接到其中一个逻辑处理器,并被置于其运行队列中。

  5. OS线程被“搁置以备将来使用”。我猜它被添加到某种线程池中。

  6. 如果goroutine进行网络I / O调用,则会以稍微不同的方式处理。

    goroutine与逻辑处理器分离,并移动到集成网络轮询器。一旦轮询器说I / O操作准备就绪,goroutine就会重新连接到逻辑处理器来处理它。

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

    我不是专家,但根据上述内容,我认为这将会发生。

    由于4个OS线程中的每一个上都有一个goroutine已经进行了阻塞系统调用,所有4个线程将从其逻辑处理器中分离出来,并且将继续阻塞,直到系统调用返回。 4个OS线程将与构成阻塞系统调用的相应goroutine相关联。

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

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

    -

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

    因此它会将其上下文与其选择的其他非阻塞线程切换。