为什么我的 goroutine 没有启动?

huangapple go评论84阅读模式
英文:

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.

huangapple
  • 本文由 发表于 2016年3月5日 04:44:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/35805694.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定