2 回答
TA贡献1820条经验 获得超2个赞
Go 1.14 版本引入了异步抢占:
Goroutines 现在是异步可抢占的。因此,没有函数调用的循环不再可能使调度程序死锁或显着延迟垃圾收集。
windows/arm
除、darwin/arm
、js/wasm
和之外的所有平台都支持此功能plan9/*
。
正如在通道是否为 goroutine 调度发送抢占点中所回答的那样?, Go 的抢占点可能会从一个版本到下一个版本发生变化。异步抢占几乎在任何地方都增加了可能的抢占点。
您对数组的写入output
未同步,并且您的oi
索引不是原子的,这意味着我们无法确定输出数组会发生什么。当然,使用互斥体为其添加原子性会引入协作调度点。虽然这些不是协作调度切换的来源(必须根据您的输出发生),但它们确实扰乱了我们对程序的理解。
数组保存了output
字符串,使用字符串可以调用垃圾回收系统,垃圾回收系统可以使用锁,导致调度切换。因此,这是在 Go-1.14 之前的实现中调度切换的最可能原因。
TA贡献1786条经验 获得超13个赞
正如@torek 所指出的那样,最流行的 GO 运行时环境已经使用抢占式调度几个月了(从 1.14 开始)。否则,goroutine 可能产生的点取决于运行时环境和版本,但威廉肯尼迪给出了一个很好的总结。
我还记得几年前在编译器中添加了一个选项来为长时间运行的循环添加屈服点,但这是一个通常不会触发的实验性选项。(当然,您可以通过runtime.GoSched
在循环中不时调用来手动执行此操作。)
至于你的测试,我对你在 Go 1.13.5 下运行时得到的结果感到惊讶。由于数据竞争,该行为并未完全定义(我知道您避免了任何同步机制以避免触发产量),但我没想到会出现这种结果。一件事是设置GOMAXPROCS
为 1 意味着只有一个 goroutine 正在并发执行,但这不一定意味着当不同的 goroutine 执行时它将在同一个核心上运行。不同的核心将具有不同的缓存和(没有同步)对 和 的值的不同output
意见oi
。
但是我可以建议你忘记修改全局变量,只在忙循环之前和之后记录一条消息。这应该清楚地表明(在 GO < 1.14 中)一次只能运行一个 lopp。(多年前我曾尝试和你做同样的实验,这似乎奏效了。)
- 2 回答
- 0 关注
- 185 浏览
添加回答
举报