3 回答

TA贡献1785条经验 获得超8个赞
无法保证 goroutine 的顺序。根据您的观察,看起来在写入通道后,主 goroutine 继续并将活动的 goroutine 打印为两个,然后squares
goroutine 运行并完成。
您也有可能从第一次调用中得到 1 来获取 goroutine 的数量。如果squares
goroutine 在主 goroutine 写入通道后立即运行,就会发生这种情况。您可以通过在写入通道之后但在获取 goroutine 数量之前添加睡眠调用来强制执行此操作。

TA贡献1833条经验 获得超4个赞
您的第二个 goroutine 接收 4 个值,打印它们并squares
几乎立即退出(返回时)。你很幸运,它在第一次调用时仍在运行NumGoRoutines
。
顺便说一句,我建议您阅读有关该语言的信息,而不是通过实验来学习。仅仅因为某些东西在您尝试时有效,并不意味着它是正确的方法并且总是有效的,尤其是在涉及并发的情况下。或者,使用竞争检测器显示任何数据竞争。

TA贡献1909条经验 获得超7个赞
让我强制执行排序,这样你甚至不需要计算 goroutine 的数量,试试这个:
package main
import (
"fmt"
"runtime"
"sync"
)
func main() {
var wg sync.WaitGroup
ch := make(chan int)
wg.Add(1)
go func() {
defer wg.Done()
for n := range ch {
fmt.Println(n)
}
}()
ch <- 1
ch <- 2
ch <- 3
ch <- 4
fmt.Println("NumGoroutine =", runtime.NumGoroutine()) // 2
close(ch)
wg.Wait()
fmt.Println("NumGoroutine =", runtime.NumGoroutine()) // 1
}
输出:
1
2
3
NumGoroutine = 2
4
NumGoroutine = 1
笔记:
使用无缓冲通道强制写入通道和从通道读取的一对一同步。
显式关闭通道以退出for循环。
显式使用wg.Done()表示 goroutine 的结束,所以wg.Wait()等待它。
让我先展开循环for:
func squares(c chan int) {
num := <-c
fmt.Println(num * num)
num = <-c
fmt.Println(num * num)
num = <-c
fmt.Println(num * num)
num = <-c
fmt.Println(num * num)
}
func main() {
c := make(chan int, 3)
go squares(c)
c <- 1
c <- 2
c <- 3
c <- 4
fmt.Println("NumGoroutine =", runtime.NumGoroutine())
time.Sleep(100 * time.Millisecond)
fmt.Println("NumGoroutine =", runtime.NumGoroutine())
}
现在让我们运行它:
由于您使用的是 3 的缓冲通道,因此这 3 行运行速度很快(这意味着无需等待通道同步 - 只需附加1, 2, 3到通道的缓冲区):
c <- 1
c <- 2
c <- 3
并且根据操作系统和 CPU 负载,消费者 goroutine 可能会全部消耗或不消耗它们,
此时c <- 4,我们有两种情况:
通道已满:所以maingoroutine 等待通道同步。
通道有一个(或多个)空闲位置:因此c <- 4运行速度很快,只是将4通道的缓冲区放入(无需等待通道同步)。
现在,在这c <- 4一点之后,我们也有两种情况:
另一个 goroutine 使用4并退出,所以我们只有一个 maingoroutine。
另一个 goroutine不消耗4,所以我们有两个goroutine。
- 3 回答
- 0 关注
- 115 浏览
添加回答
举报