gpt4 book ai didi

go - 为什么这个 Go 代码会阻塞?

转载 作者:IT老高 更新时间:2023-10-28 13:06:45 26 4
gpt4 key购买 nike

我写了以下程序:

package main

import (
"fmt"
)

func processevents(list chan func()) {
for {
//a := <-list
//a()
}
}

func test() {
fmt.Println("Ho!")
}

func main() {

eventlist := make(chan func(), 100)

go processevents(eventlist)

for {
eventlist <- test
fmt.Println("Hey!")
}
}

由于 channel 事件列表是一个缓冲 channel ,我想我应该得到输出“嘿!”的 100 倍,但它只显示一次。我的错在哪里?

最佳答案

更新(Go 版本 1.2+)

从 Go 1.2 开始,调度程序的工作原理是抢占式多任务。这意味着原始问题中的问题(以及下面提供的解决方案)不再相关。

来自 Go 1.2 release notes

Pre-emption in the scheduler

In prior releases, a goroutine that was looping forever could starve out other goroutines on the same thread, a serious problem when GOMAXPROCS provided only one user thread. In Go > 1.2, this is partially addressed: The scheduler is invoked occasionally upon entry to a function. This means that any loop that includes a (non-inlined) function call can be pre-empted, allowing other goroutines to run on the same thread.

简答

它不会阻止写入。它陷入了processevents的无限循环。这个循环永远不会屈服于调度程序,导致所有 goroutine 无限期地锁定。

如果您注释掉对 processevents 的调用,您将获得预期的结果,直到第 100 次写入。此时程序会出现 panic ,因为没有人从 channel 中读取数据。

另一种解决方案是在循环中调用 runtime.Gosched()

长答案

在 Go1.0.2 中,Go 的调度器按照 Cooperative multitasking 的原理工作。 .这意味着它通过让这些例程在特定条件下与调度程序交互来将 CPU 时间分配给在给定 OS 线程中运行的各种 goroutine。这些“交互”发生在 goroutine 中执行某些类型的代码时。在 Go 中,这涉及到执行某种 I/O、系统调用或内存分配(在某些条件下)。

在空循环的情况下,不会遇到这样的情况。因此,只要该循环正在运行,就永远不允许调度程序运行其调度算法。因此,这可以防止它将 CPU 时间分配给等待运行的其他 goroutine,并且您观察到的结果随之而来:您有效地创建了一个无法被调度程序检测或打破的死锁。

在 Go 中通常不需要空循环,并且在大多数情况下表明程序中存在错误。如果出于某种原因确实需要它,则必须通过在每次迭代中调用 runtime.Gosched() 手动让步给调度程序。

for {
runtime.Gosched()
}

GOMAXPROCS 设置为值 > 1 作为解决方案被提及。虽然这将消除您观察到的直接问题,但如果调度程序决定将循环 goroutine 移动到它自己的 OS 线程,它将有效地将问题移动到不同的 OS 线程。不能保证这一点,除非您在 processevents 函数的开头调用 runtime.LockOSThread()。即使那样,我仍然不会依赖这种方法来成为一个好的解决方案。只需在循环本身中调用 runtime.Gosched() 即可解决所有问题,无论 goroutine 在哪个操作系统线程中运行。

关于go - 为什么这个 Go 代码会阻塞?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12413510/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com