关于go routine在go routine中的行为
About the behavior of go routine in go routine
我是 golang 的新手,正在研究 goroutine。
我特意用 goroutine 写了简单的除数代码。
首先,我给出底数,不断除以它的数,直到不可整除
但是,我将 go split(n)
更改为 split(n)
,它并没有像下面这样工作,这是为什么?
■ 源代码
package main
import (
"flag"
"fmt"
"log"
"net/http"
"os"
"strconv"
)
var next = make(chan int)
var quit = make(chan int)
func divide(n int) {
defer func(){ quit <- 1 }()
fmt.Println("[divide] n = " + strconv.Itoa(n))
r := n % 2
if r == 0 {
next <- n / 2
}
}
func execute() {
fmt.Println("[execute] start")
count := 0
end := false
for !end {
select {
case n := <- next:
count++
fmt.Println("[execute] n = " + strconv.Itoa(n) + ", count = " + strconv.Itoa(count))
go divide(n)
case _ = <- quit:
count--
fmt.Println("[execute] end. count = " + strconv.Itoa(count))
if count <= 0 {
end = true
}
}
}
fmt.Println("complete")
os.Exit(0)
}
func main() {
base := flag.Int("n", 1, "Input the number")
flag.Parse()
if *base <= 0 {
fmt.Println("please more than 1")
os.Exit(0)
}
go execute()
next <- *base
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatal("ListenAndSearver:", err)
}
}
■ 结果(工作正常)
$ go run main.go -n 6
[execute] start
[execute] n = 6, count = 1
[divide] n = 6
[execute] n = 3, count = 2
[execute] end. count = 1
[divide] n = 3
[execute] end. count = 0
complete
■ 结果(无效)
$ go run main.go -n 6
[execute] start
[execute] n = 6, count = 1
[divide] n = 6
没有 go divide()
内部执行:
- execute() 从
next
通道读取,调用 divide
- divide() 等待写入
next
- execute() 仍在等待 divide() 到 return,所以程序现在死锁了。
在go divide()
里面执行:
- execute() 从
next
通道读取,在新的 goroutine 中启动 divide
,继续等待
- divide() 写入
next
- execute() 从
next
读取,启动另一个 goroutine,等等
请注意,一旦 divide
写入 next
,它就会继续写入 quit
,因此您可能会在一切完成之前收到多条退出消息。
我是 golang 的新手,正在研究 goroutine。
我特意用 goroutine 写了简单的除数代码。
首先,我给出底数,不断除以它的数,直到不可整除
但是,我将 go split(n)
更改为 split(n)
,它并没有像下面这样工作,这是为什么?
■ 源代码
package main
import (
"flag"
"fmt"
"log"
"net/http"
"os"
"strconv"
)
var next = make(chan int)
var quit = make(chan int)
func divide(n int) {
defer func(){ quit <- 1 }()
fmt.Println("[divide] n = " + strconv.Itoa(n))
r := n % 2
if r == 0 {
next <- n / 2
}
}
func execute() {
fmt.Println("[execute] start")
count := 0
end := false
for !end {
select {
case n := <- next:
count++
fmt.Println("[execute] n = " + strconv.Itoa(n) + ", count = " + strconv.Itoa(count))
go divide(n)
case _ = <- quit:
count--
fmt.Println("[execute] end. count = " + strconv.Itoa(count))
if count <= 0 {
end = true
}
}
}
fmt.Println("complete")
os.Exit(0)
}
func main() {
base := flag.Int("n", 1, "Input the number")
flag.Parse()
if *base <= 0 {
fmt.Println("please more than 1")
os.Exit(0)
}
go execute()
next <- *base
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatal("ListenAndSearver:", err)
}
}
■ 结果(工作正常)
$ go run main.go -n 6
[execute] start
[execute] n = 6, count = 1
[divide] n = 6
[execute] n = 3, count = 2
[execute] end. count = 1
[divide] n = 3
[execute] end. count = 0
complete
■ 结果(无效)
$ go run main.go -n 6
[execute] start
[execute] n = 6, count = 1
[divide] n = 6
没有 go divide()
内部执行:
- execute() 从
next
通道读取,调用divide
- divide() 等待写入
next
- execute() 仍在等待 divide() 到 return,所以程序现在死锁了。
在go divide()
里面执行:
- execute() 从
next
通道读取,在新的 goroutine 中启动divide
,继续等待 - divide() 写入
next
- execute() 从
next
读取,启动另一个 goroutine,等等
请注意,一旦 divide
写入 next
,它就会继续写入 quit
,因此您可能会在一切完成之前收到多条退出消息。