英文:
Why do we need to call runtime.Gosched after call to atomic.AddUint64 and other similar atomic ops?
问题
通过*Go by Example: Atomic Counters*。代码示例在调用atomic.AddUint64
之后调用了runtime.Gosched
。
调用atomic.AddUint64
是为了
不幸的是,我发现这个解释并不充实和令人满意。
我尝试运行了示例代码(为了简洁起见,删除了注释):
package main
import "fmt"
import "time"
import "sync/atomic"
import "runtime"
func main() {
var ops uint64 = 0
for i := 0; i < 50; i++ {
go func() {
for {
atomic.AddUint64(&ops, 1)
runtime.Gosched()
}
}()
}
time.Sleep(time.Second)
opsFinal := atomic.LoadUint64(&ops)
fmt.Println("ops:", opsFinal)
}
没有使用runtime.Gosched()
(go run conc.go
),即使我将循环从50减少到1,程序也从未退出。
问题:
在调用atomic.AddUint64
之后,在底层发生了什么,以至于需要调用runtime.Gosched
?runtime.Gosched
是如何解决这个问题的?我在sync/atomic
的文档中没有找到任何关于这方面的提示。
英文:
Going through Go by Example: Atomic Counters. The code example calls runtime.Gosched
after calling atomic.AddUint64
.
atomic.AddUint64
is called to
> ensure that this goroutine doesn’t starve the scheduler
Unfortunately, I am finding the explanation not so meaty and satisfying.
I tried running the sample code (comments removed for conciseness):
package main
import "fmt"
import "time"
import "sync/atomic"
import "runtime"
func main() {
var ops uint64 = 0
for i := 0; i < 50; i++ {
go func() {
for {
atomic.AddUint64(&ops, 1)
runtime.Gosched()
}
}()
}
time.Sleep(time.Second)
opsFinal := atomic.LoadUint64(&ops)
fmt.Println("ops:", opsFinal)
}
without the runtime.Gosched()
(go run conc.go
) and the program never exited even when I reduced the loop from 50 to 1.
Question:
What happens under the hood after the call to atomic.AddUint64
that it is necessary to call runtime.Gosched
? And how does runtime.Gosched
fixes this? I did not find any hint to such a thing in sync/atomic
's documentation.
答案1
得分: 5
这是合作式多线程的工作原理。如果一个线程保持就绪状态,它将继续运行,而其他线程则不会运行。使用显式和隐式的抢占点来允许其他线程运行。如果你的线程在一个循环中停留了很长时间而没有隐式的抢占点,如果你不添加一个显式的抢占点,你将会饿死其他线程。
这个答案提供了关于Go语言何时使用合作式多线程的更多信息。
英文:
This is how cooperative multithreading works. If one thread remains ready to run, it continues to run and other threads don't. Explicit and implicit pre-emption points are used to allow other threads to run. If your thread has a loop that it stays in for lots of time with no implicit pre-emption points, you'll starve other threads if you don't add an explicit pre-emption point.
This answer has much more information about when Go uses cooperative multithreading.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论