package main
var a string
func f() {
print(a)
}
func hello() {
a = "hello, world"
go f()
}
func main() {
hello()
}
输出:
不确定
可能调用hello函数的某一时刻打印;可能
hello
函数执行完成后打印;可能不打印"hello world"
原因:
例2执行
go f()
语句创建Goroutine和hello
函数是在同一个Goroutine中执行, 根据语句的书写顺序可以确定Goroutine的创建发生在hello
函数返回之前, 但是新创建Goroutine对应的f()
的执行事件和hello
函数返回的事件则是不可排序的,也就是并发的。故不确定f()执行打印语句和hello函数返回谁先谁后,所以可能在hello函数返回之前或返回之后打印;如果hello函数返回了且main函数也退出了,那么程序就退出了,打印语句不会再执行。
package main
import (
"fmt"
)
func main() {
ch := make(chan int)
fmt.Println(<-ch)
go func(){
ch <- 1
}()
}
输出:
原因:
例3main函数执行到第9行时,要从通道ch取值,此时main协程会被阻塞,等待向通道存值的 *** 作;而在main协程中程序是顺序执行的,如果第9行一直阻塞着,下面的go协程也不可能执行,main协程也永远等不来向通道存值的 *** 作;运行时会检查主协程是否在等待,如果是则判定为死锁。
package main
import (
"time"
)
func main() {
ch1 := make(chan string)
ch2 := make(chan string)
go func() {
ch2 <- "ch2 value"
ch1 <- "ch1 value"
}()
go func() {
<- ch1
<- ch2
}()
time.Sleep(time.Second * 2)
print("main done")
}
输出:
main done
原因:
例4main函数顺序执行到第8行时,此时摆在面前的有3个协程:2个go协程和main协程,它们的执行是并发的,谁都有可能先发生。main协程第19行休眠2s,保证main协程不会太快执行完,因为如果main函数执行结束,程序会退出,不会等待其他非main协程结束;不管这2个go协程哪个先执行,都会导致2个go协程都被阻塞等待;此时main协程休眠完,执行完第20行,程序退出。尽管2个go协程互相阻塞,但和main协程无关,故不会报死锁错误。
package main
var done = make(chan bool, 1)
var msg string
func aGoroutine() {
msg = "hello, world"
<-done
}
func main() {
go aGoroutine()
done <- true
println(msg)
}
输出:
2种可能:
打印为空或打印"hello world"
原因:
通道done是带缓冲的,
main协程
的done <- true
接收 *** 作将不会被后台协程的<-done
接收 *** 作阻塞,若第14行打印语句早于aGoroutine协程对msg赋值执行,则打印为空;若msg赋值早于打印语句执行,则打印"hello world"。
参考:
https://learnku.com/docs/the-way-to-go/142-covariance-channel/3686
https://juejin.cn/post/6844903881843933197
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)