如何去运行时检查是否够程受阻?

问题描述 投票:3回答:3

转到文档说:

当一个协程块,例如通过调用一个阻塞系统调用,运行时自动地移动在同一操作系统线程其他协程到一个不同的,可运行的线程,以便它们不会被阻塞

但如何运行检测的goroutine被阻止?

例如,如果我会去例程的一个运行计算将其评价为阻塞操作?

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")
}

我得到的结果:巴兹,嘘吧。但为什么?是否转到明白foo阻止?

go concurrency goroutine
3个回答
2
投票

这张票是相关的问题:

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

你可以做的每个阻塞call,将被运行时服务。因此,运行时知道如果事情发生这可能阻塞。

例如:

  1. 如果你调用Lock()sync.Mutex运行时会处理这一点,检查阉会阻止或不采取相应的行动。
  2. 如果您在Run()致电Output()exec.Cmd(或类似)运行时注意到,并假定,这个调用将阻塞。它不能知道无论您正在运行将阻止该程序,所以它必须承担最坏的打算。

据我所知,有两个主要的机制,如何够程可以阻止和上面的例子是为每一个例子。

  1. 是对事物的运行时提供给您没有“外部”帮助一个例子。
  2. 是事物的例子是一个系统调用是参与。在Linux例如Golang不使用GNU libc和实现它通过调用操作系统需要直接的系统调用。所有这些调用都是通过包syscall去(据我所知),这里的运行时间有单钩得到通知会发生什么。

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

就问题的代码:否。不理解使得f可能需要大量的时间,如果循环不被编译器优化掉。而在这样一个紧密的循环中,去调度不能“停止”的够程,并设置另一个与运行,因为在循环中没有抢占点。所以,如果你有这样的够程的多张做紧密循环不抢占点,他们可能会吃了你的CPU和所有其它够程必须等待,直到紧密的循环中的至少一个已经完成。但是,只有在调用该循环不同的功能改变了图片,是一个函数调用是一个抢占点。

user1432751问评论:

用什么CPU寄存器时发生阻塞操作是怎样呢?当前线程被阻塞够程,去调度创建新的系统线程,并迁移所有其他线程呢? -

转到时间表是不可抢占(至少是国家我最后一次检查),但在某些抢占点计划。例如系统调用,发送和等待的渠道,如果我没有记错的函数调用。因此,在这些点的内部函数被调用,CPU寄存器相应和堆栈上的够程执行已代码,当调度程序决定该怎么做。

是的,如果一个系统调用完成,因此有被阻止的操作系统线程的危险,该够程做系统调用都有自己的操作系统线程,甚至不指望GOMAXPROCS。


1
投票

当一个够程已要求运行时做的工作,通常是通过系统调用在这种情况下阻塞通常发生。听一个插座上,例如 - 的够程告诉系统的kqueue / epoll的部分当数据到达,此时它是非常明显受阻将其唤醒。

够程的一个通道上等待消息时,还封锁 - 这里的够程已明确告知,它不会,直到它收到一个消息,在做别的运行,所以运行时知道的很清楚,够程受阻。

大多数操作表单的“做到这一点,给我一个结果”或“给我这个当它准备”都是可核查的阻塞操作,并进入休眠状态,直到准备。


0
投票

我几个月前得到了同样的问题,我解决它补充说,应该在更短的一定时间进行更新,像看门狗通道:

out := make(chan bool)      
go func() {             
    for {
        // Do some stuff here
        time.Sleep(10 * time.Millisecond) // leaves CPU free for 10ms
        out <- true             
    }
}()     
// main loop
for { 
    select {            
        case <-out: // Jump here when out channel is filled             
        case <-time.After(10 * time.Second): // Jump here if there is no channel activity for 10s
    }       
}

我希望这将是对你有用。

© www.soinside.com 2019 - 2024. All rights reserved.