Golang Go语言协程执行问题请教
Golang Go语言协程执行问题请教
package main
import (
“fmt”
“time”
)
var x = 0
func main() {
var num = 123
var p = &num
c := make(chan int)
go func() {
c <- *p + x // 1. 返回 123
// c <- *p // 2. 返回 789
}()
time.Sleep(time.Second)
num = 789
fmt.Println(<-c)
}
子协程,执行 1 返回 123,执行 2 返回 789
没看出来有什么差别啊?
更多关于Golang Go语言协程执行问题请教的实战教程也可以访问 https://www.itying.com/category-94-b0.html
有区别,
1 进行了运算,取运算后的结果,你加了 1 秒的延时,很明显当时的 num 的值为 123,所以输出是 123,如果去掉延时,则为 789
2 一直指向 num 的地址,从通道里读的时候读的是 789
更多关于Golang Go语言协程执行问题请教的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
time.Sleep 不能保证 goroutine 一定比 main 先执行,如果想要让 Goroutine 比 main 先执行的话,可以通过 waitGroup 来同步:
https://gist.github.com/bwangelme/5e71895d40130521b71828cef72adc1f
c <- *p + x // 1. 返回 123 等于 tmp:= *p + x ; c<- tmp ,因为 chan 的 size 是 0 所以要等到主进程到 fmt.Println(<-c)时才会运行 c<- tmp
”By default channels are unbuffered, meaning that they will only accept sends (chan <-) if there is a corresponding receive (<- chan) ready to receive the sent value“
正解
正解, 1 2 楼答的不是这个问题
按照这个说法的话,应该两个值都会返回 123 才对啊?
为啥第 1 种返回 123,第 2 种返回 789
1 运算了,2 为啥不运算呢?
#7 2,向通道发送的 num 的地址,此时通道是阻塞的,过一秒后 num 因为赋值 789 地址发生改变,然后从通道里读取 num 值是 789
感谢
ch <- expression
expression 计算的时机是问题的关键。
具体的细节,希望大牛们给详细说说
这个问题和抛硬币一样。
c <-*p + x,既可能返回 123,也可能返回 789 。这和 thread 切换,先跑了哪个指令有关系(先跑了 num=789 还是后跑了),你可以把 sleep 时间修改小,证明这个现象。go<br>package main<br><br>import (<br> "fmt"<br> "time"<br>)<br><br>var x = 0 <br><br>func call() {<br> var num = 123 <br> var p = &num<br> c := make(chan int)<br> go func() {<br> c <- *p + x // 1. 返回 123<br> // c <- *p // 2. 返回 789<br> }() <br> time.Sleep(time.Second / 1000)<br> num = 789 <br> readValue := <-c <br> if readValue == 789 {<br> fmt.Printf("hello 789\n")<br> } <br> //fmt.Println(readValue)<br>}<br><br>func main() {<br> for i := 0; i < 1000000; i++ {<br> call()<br> } <br>}<br><br>
在 6c6t 的 cpu 上跑了一下,出现了一次 789 。
能详细解释下 1 这种情况既可能返回 123,也可能返回 789 吗?
主协程 sleep 1s,基本本可能输出 789 了。
如果主协程 sleep 时间很短,那么 num = 789 可能会比*p + x 先执行
这两天有点事就没有回答两位的问题。刚刚做了一些试验,发现了更有意思的地方。
1.如果写 chan 的地方是算术表达式,go 会提前进行预处理(对 c<-*p+0),可能已经换成 c<-123,所有大概率返回 123
2.如果是值,就换按正常逻辑往下走。time.Sleep 之后,两个 go 程开始了竞争,num=789 的执行速度,比唤醒生产者 chan+写数据快,所有大概率返回 789 。
当然上面从数据中总结的规律特别依赖 go 的版本(go 1.13.1),大家也不要太在意。也许哪天人家(Go Core Team)就改了。就当乐一乐,原来 go 还有一些小动作。go<br>package main<br><br>import (<br> "fmt"<br> "time"<br>)<br><br>var x = 0<br><br>func call() {<br> var num = 123<br> var p = &num<br> c := make(chan int)<br> go func() {<br> //c <- *p + 0 //大概率返回 123<br> c <- *p // 大概率返回 789<br> }()<br> time.Sleep(time.Second / 1000)<br> num = 789<br> readValue := <-c<br> if readValue == 123 {<br> fmt.Printf("hello %d\n", readValue)<br> }<br>}<br><br>func main() {<br> for i := 0; i < 1000000; i++ {<br> call()<br> }<br>}<br><br>
俺老孙直言,V2EX 这个防 spam 系统真的是人工智障
[TIP - 如何在回复中贴代码]( /t/663565 )
针对您提出的Golang协程执行问题,以下是一些专业的解答和建议:
-
协程无法正常运行的原因:
- 未正确使用
sync.Mutex
或sync.RWMutex
,可能导致死锁或资源竞争。 - 协程阻塞,如等待I/O操作,可能导致其他协程饥饿。
- 竞态条件,多个协程同时访问共享资源时未加锁或通信。
- 未正确使用
-
协程的正确使用:
- 使用
go
语句启动协程,确保函数在新协程中执行。 - 使用
channel
进行协程间通信,确保数据一致性和安全性。 - 使用
sync.WaitGroup
等同步工具,等待一组协程完成后再执行后续操作。
- 使用
-
协程调度和管理:
- 避免协程泄漏,使用
context
包管理协程生命周期。 - 优化协程创建和执行策略,减少不必要的协程创建,提高性能。
- 监控和调整系统资源分配,确保协程公平获取执行机会。
- 避免协程泄漏,使用
-
建议:
- 在编写Go代码时,注意程序的健壮性,对协程的错误进行适当处理。
- 对于涉及系统调用的操作,考虑设置超时时间或使用非阻塞I/O。
希望以上解答和建议能帮助您解决Golang协程执行问题。如有更多疑问,欢迎继续提问。