出发地:http://blog.nindalf.com/how-goroutines-work/

由于goroutine是协同调度的,连续循环的goroutine可能会使同一线程上的其他goroutine挨饿.

Goroutine很便宜,如果它们被阻塞,不会导致将它们多路复用到挡路的线程

  • 网络输入
  • 睡觉
  • 渠道运营或
  • 阻止同步包中的基元.

因此,假设您有一些类似下面这样的代码,它除了随机循环几次并打印总和之外,什么也不做:

func sum(x int) {
  sum := 0
  for i := 0; i < x; i++ {
    sum += i
  }
  fmt.Println(sum)
}

如果您使用如下的Goroutine

go sum(100)
go sum(200)
go sum(300)
go sum(400)

如果您只有一个线程,Goroutine会一个接一个地运行吗?

推荐答案

所有克雷克 comments 的汇编和整理.

抢占式意味着内核(运行时)允许线程运行特定的时间量,然后在其他线程不做任何事情或不知道任何事情的情况下执行它们.在操作系统内核中,这通常是使用硬件中断实现的.进程不能挡路整个操作系统.在协作多任务中,线程必须显式地将执行交给其他线程.如果不这样做,它可能会挡路整个过程,甚至整台机器.围棋就是这样做的.它有一些非常具体的点,在那里Goroutine可以产生处决.但是,如果goroutine只为{}执行,那么它将锁定整个进程.

但是,这句话并没有提到运行时的最新变化.fmt.Println(sum)可能会导致其他Goroutine被调度,因为较新的运行时将在函数调用上调用调度程序.

If you don't have any function calls, just some math, then yes, goroutine will lock the thread until it exits or hits something that could yield execution to others. That's why for {} doesn't work in Go. Even worse, it will still lead to process hanging even if GOMAXPROCS > 1 because of how GC works, but in any case you shouldn't depend on that. It's good to understand that stuff but don't count on it. There is even a proposal to insert scheduler calls in loops like yours

Go的运行时所做的主要事情是,它尽最大努力让每个人都可以执行,而不会让任何人挨饿.它如何做到这一点没有在语言规范中指定,并且在future 可能会改变.如果将实现关于循环的建议,那么即使没有函数调用,也可能发生切换.目前,您唯一应该记住的是,在某些情况下,函数调用可能会导致goroutine执行.

为了解释Akavall答案中的切换,当调用fmt.Printf时,它做的第一件事是判断是否需要增加堆栈并调用调度器.它可能会切换到另一条猩猩路由.它是否会切换取决于其他Goroutine的状态和调度器的确切实现.与任何调度器一样,它可能会判断是否有应该执行的饥饿Goroutines.对于多次迭代,函数调用有更大的机会进行切换,因为其他函数的饥饿时间更长.由于迭代次数很少,猩猩在饥饿发生之前就结束了.

Go相关问答推荐

如何在定制普罗米修斯出口商中测试动态计量注册?

在Golang中,@LATEST和@UPGRADE特殊查询有什么不同?

使用ciph.AEAD.Seal()查看内存使用情况

如何在v2 Go SDK中使用KeyConditionExpression查询AWS DynamoDb?

如何执行asn 1 marshal/unmarshal和omit字段?

通过渠道和goroutines增值1000倍

如何测试 Zerolog 记录器引发类型错误的日志(log)事件?

无效操作:v > max(类型参数 T 与 > 不可比较)

如何根据地址和大小打印字符串

使用GOTK3和librsvg在Go中如何加载内联SVG?

Golang 发送Post请求出现400错误

Global Thread-local Storage 在 Go 中的可行性和最佳实践

Yocto 无法交叉编译 GoLang Wails 应用程序

golang yaml 马歇尔网址

判断不同 go map 类型中的重复键

从 Makefile 运行时权限被拒绝

跟踪长时间运行的任务的进度 - 正确的方法

Golang SSH客户端错误无法验证,try 的方法[无公钥],没有支持的方法

如何使用 httputil.ReverseProxy 设置 X-Forwarded-For

Go http标准库中的内存泄漏?