2017-10-08 70 views
2

转到文档说:Go运行时如何检查goroutine是否被阻止?

当协程块,如通过调用拦截系统调用,所以他们赢得了运行时自动移动在同一操作系统线程其他协同程序的不同,运行的线程不会被阻止

但是,运行时如何检测到goroutine被阻塞?

例如,如果我将在go-routine之一中运行计算,它会被评估为阻塞操作吗?

package main 

import (
    "fmt" 
    "runtime" 
) 

func f(from string, score int) { 
    for i := 0; i < score; i++ { 
      for z := 0; z < score; z++ { 
     } 
    } 

    fmt.Println(from, " Done") 
} 

func main() { 
runtime.GOMAXPROCS(1) 
f("direct", 300000) 
go f("foo", 200000) 
go f("bar", 20000) 
go f("baz", 2000) 

go func(msg string) { 
     fmt.Println(msg) 
    }("going without loop") 

     var input string 
    fmt.Scanln(&input) 
    fmt.Println("done") 
} 

我得到的结果:巴兹,嘘酒吧。但为什么? Go了解foo是否阻止?

+0

http://blog.alexnesterov.com/post/coroutines-part-1/也是一个有趣的阅读(对于Kotlin,但提及Go) – VonC

回答

1

这张票是相关的问题:

https://github.com/golang/go/issues/11462

每个阻塞调用你可以做,将被运行时服务。所以运行时知道是否会发生可能阻塞的事情。

例如:

  1. 如果您在sync.Mutex调用Lock()运行时会处理这一点,检查阉会阻止或不采取相应的行动。

  2. 如果您在exec.Cmd上调用Run()Output()(或类似),运行时会通知并假定此调用将被阻止。它不知道你正在运行的程序会阻塞,所以它必须假设最差。

据我所知,有两个原则机制,一个goroutine可以如何阻塞,上面的例子是每个例子。

  1. 是运行时没有“外部”帮助提供给您的示例。

  2. 是一个涉及系统调用的例子。 Linux上的Golang例如不使用gnu libc,并通过调用os直接实现它需要的系统调用。所有这些调用都通过包syscall(据我所知),在这里运行时有一个钩子来获得通知发生了什么。

当然的画有点浑浊,因为它可能是,该golang从OS为OS跨线程同步即使对于需要1互斥,然后将其还以某种方式有点例2

关于问题中的代码:不知道,如果循环没有被编译器优化,那么f可能会花费很多时间。在这样一个紧密的循环中,go调度程序不能“停止”goroutine并将另一个设置为running,因为循环中没有抢占点。因此,如果你有多个这样的套房在没有抢占点的情况下执行紧密环路 ,他们可能会吃掉你的cpus,并且所有其他套餐必须等待,直到至少有一个紧密环路完成。 但是只有在该循环中调用不同的函数才能更改该图片,因此作为函数调用的 是抢占点。

user1432751在评论问:

什么阻塞操作是发生在与CPU寄存器发生什么呢? 当前线程被goroutines阻塞,Go计划程序创建新的 系统线程并迁移其中的所有其他线程? -

转入时间表不是预先约定的(至少这是我上次检查时的状态),而是在某些抢占点的时间表。例如系统调用,发送并在频道上等待,如果我没有记错函数调用。所以在这些点上调用一个内部函数,当调度器决定要做什么时,cpu寄存器相对于在goroutine中执行的代码已经在栈中。

是的,如果一个系统调用完成并因此存在被阻塞的os线程的危险,那么执行系统调用的goroutine会得到自己的os线程,甚至不会计算到GOMAXPROCS。

+0

阻塞操作发生时,CPU寄存器会发生什么?当前线程被goroutine阻塞,Go调度程序创建新的系统线程并迁移其中的所有其他线程? –

+0

我在回答这个问题时回答了你的评论。 – Krom

1

通常通过系统调用,当goroutine要求运行时执行工作时,通常会在此情况下发生阻塞。例如,听一个套接字 - goroutine告诉系统的kqueue/epoll部分在数据到达时将其唤醒,此时它明显被阻塞。

当等待通道上的消息时,Goroutines也被阻塞 - 这里goroutine已经明确地告诉运行时,在接收到消息之前它不会做任何其他事情,因此运行时非常清楚该goroutine是受阻。

形式为“做到这一点,并给我一个结果”或“准备就绪时给我这个表单”的大多数操作都是可验证的阻止操作,并进入睡眠状态直到准备就绪。

相关问题