英文:
Why aren't my goroutines launched?
问题
不,不是因为我的程序结束得太快。
我有这个脚本:
package main
import ("log"; "io/ioutil"; "strings")
const BASE_FILE_NAME = "abc_"
func mygoroutine(file_name string) {
log.Println("在文件", file_name, "的goroutine中")
}
func get_file_names() []string {
file_names := make([]string, 0)
files, _ := ioutil.ReadDir("./")
for _, file := range files {
if strings.HasPrefix(file.Name(), BASE_FILE_NAME) {
file_names = append(file_names, file.Name())
}
}
return file_names
}
func main() {
file_names := get_file_names()
for _, file_name := range file_names {
log.Println("现在启动文件", file_name, "的goroutine")
go mygoroutine(file_name)
}
log.Println("启动完成。")
for {}
log.Println("现在退出")
}
在包含可执行文件的目录中,我有两个以abc_
开头的文件,所以输出结果是:
2016/03/04 20:35:14 现在启动文件 abc_fr 的goroutine
2016/03/04 20:35:14 现在启动文件 abc_hrty 的goroutine
2016/03/04 20:35:14 启动完成。
脚本不会停止,它永远不会记录现在退出
的消息,因为它在空的for
循环中循环。但是我没有看到In goroutine for file
的消息。
为什么会这样?我做错了什么?
谢谢帮助!
英文:
No, it's not because my program ends too fast.
I have this script:
package main
import ("log"; "io/ioutil"; "strings")
const BASE_FILE_NAME = "abc_"
func mygoroutine(file_name string) {
log.Println("In goroutine for file", file_name)
}
func get_file_names() []string {
file_names := make([]string, 0)
files, _ := ioutil.ReadDir("./")
for _, file := range files {
if strings.HasPrefix(file.Name(), BASE_FILE_NAME) {
file_names = append(file_names, file.Name())
}
}
return file_names
}
func main() {
file_names := get_file_names()
for _, file_name := range file_names {
log.Println("Now lunching goroutine for file", file_name)
go mygoroutine(file_name)
}
log.Println("Finished launching.")
for {}
log.Println("Now exiting")
}
In the directory that contains the executable, I have two files that start with abc_
so the output is this:
2016/03/04 20:35:14 Now lunching goroutine for file abc_fr
2016/03/04 20:35:14 Now lunching goroutine for file abc_hrty
2016/03/04 20:35:14 Finished launching.
The script doesn't stop, it never logs Now exiting
, because it loops in the empty for. But I do not see the In goroutine for file
message.
Why is this happening? What am I doing wrong?
Thanks for the help!
答案1
得分: 6
如果你的程序在GOMAXPROCS=1
(即单个操作系统线程)下运行,for{}
会导致它冻结,从而不会让Go的用户模式调度器运行。这是与此相关的问题。JimB指出,无论GOMAXPROCS
如何,它都会引起其他问题;最终,运行时必须停止你的goroutine进行垃圾回收,但它无法停止for{}
。
将for{}
更改为select{}
可以让调度器运行,并且不会占用CPU。在这个简化的程序中,你的goroutine代码会运行。它以"all goroutines are asleep - deadlock!"结束,因为你的其他goroutine退出了,只剩下一个(main)goroutine被挂在select{}
上。
package main
import "log"
const BASE_FILE_NAME = "abc_"
func mygoroutine(file_name string) {
log.Println("In goroutine for file", file_name)
}
func main() {
go mygoroutine("foo")
log.Println("Finished launching.")
select {}
log.Println("Now exiting")
}
当然,通常情况下,即使使用select{}
也不希望让goroutine挂起;这会导致一些资源在程序结束之前一直被占用。要构建有用的东西,你需要使用其他东西,比如sync.WaitGroup
或通道。
英文:
If your program is running with GOMAXPROCS=1
(that is, a single OS thread), for{}
freezes it without ever letting Go's user-mode scheduler run. This is the issue about it. JimB points out it causes other problems regardless of GOMAXPROCS
; eventually the runtime has to stop your goroutine for garbage collection, and it can't stop for{}
.
Changing for{}
to select{}
lets the scheduler run and doesn't eat CPU. In this reduced program, your goroutine code runs. It ends with "all goroutines are asleep - deadlock!" because your other goroutine quits and the only remaining one (main) is hung in the select{}
.
package main
import "log"
const BASE_FILE_NAME = "abc_"
func mygoroutine(file_name string) {
log.Println("In goroutine for file", file_name)
}
func main() {
go mygoroutine("foo")
log.Println("Finished launching.")
select {}
log.Println("Now exiting")
}
Of course, you normally don't want to hang a goroutine even with select{}
; that's going to leave some resources in use until your program ends. To build something useful you'll need something else like a sync.WaitGroup
or channel.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论