为了账号安全,请及时绑定邮箱和手机立即绑定

为什么我需要睡两次才能看到 goroutines?

为什么我需要睡两次才能看到 goroutines?

Go
catspeake 2022-01-10 15:14:04
我用 go 编写了这个小程序。关于go关键字,我只知道当我以这种方式调用一个函数时,是同时执行的。我尝试在没有 time.Sleep() 的情况下执行此代码,但没有生成输出。我需要添加 time.Sleep(1000) 两次。一次。睡眠声明是不够的。为什么?package mainimport (    "fmt"    "time")func doSomething(integer int) {    fmt.Println(integer)}func main() {    i := 1    for i <= 10 {        go doSomething(i)        i++    }    time.Sleep(1000)    time.Sleep(1000)}
查看完整描述

2 回答

?
www说

TA贡献1775条经验 获得超8个赞

这是因为当您使用go(即作为 goroutine)调用函数时,它会在后台运行并继续执行。在这种情况下,在调用 goroutine 后,程序没有任何事情可做,所以它只是完成并且您看不到任何输出。为什么需要两个?好吧,您没有,只是 1 秒的睡眠时间不够长,如果您有,time.Sleep(2000)您可能会得到相同的结果(尽管不能保证)。通常,在使用 goroutine 时,您需要在某些地方使用某种阻塞语句。imo,最简单的方法是将通道传递给 goroutine,然后从它接收。

由于代码的结构,这不是最有用的示例,但这是您的程序的修改版本,它将阻塞直到第一个 goroutine 完成。由于您实际上调用了 10 个 goroutine,因此您需要更强大的逻辑来阻止它们,直到它们完成,但更合理的解决方案是将循环放入 gouroutine,而不是调用 10 个 goroutine。https://play.golang.org/p/66g9u8Bhjj

另外,请在 go tour 中查看这个更真实的示例;https://tour.golang.org/concurrency/2


查看完整回答
反对 回复 2022-01-10
?
蝴蝶不菲

TA贡献1810条经验 获得超4个赞

试试这个:


package main


import (

    "fmt"

    "runtime"

    "time"

)


func doSomething(integer int) {

    fmt.Println(integer)

}


func main() {

    i := 1


    for i <= 10 {

        go doSomething(i)

        i++

    }

    runtime.Gosched()

    time.Sleep(10 * time.Millisecond)

}

它会以不同的方式运行。


你知道完成这个(你的)代码需要多少时间:(

考虑 CPU 负载 100%,其他进程具有更高的优先级。)


func doSomething(integer int) {

    fmt.Println(integer)

}

for i <= 10 {

    go doSomething(i)

    i++

}

简单的回答:没有。

它取决于每个系统上的许多未知因素:

1- CPU 速度和 CPU 内核和 CPU 缓存的数量...

2- RAM 速度和总线速度以及总线矩阵(是否并发?)

2- 操作系统调度程序和操作系统负载和优先级

3- Golang 调度程序

4- CPU 负载

...


我的意思是:在并发系统和并发编程中,依赖简单的代码(或汇编)指令时序并不是一个好主意。


是的,了解 Golang 调度器及其工作原理是件好事,但是即使你知道 Golang 调度器的行为方式,你知道操作系统现在在做什么吗?


仅在实时操作系统中,它估计为毫秒左右范围内的某个已知时间。


甚至有时最好限制并发:

这是限制并发的一种方法:


//using chan to limit the concurrency

package main


import (

    "os/exec"

    "runtime"

    "sync"

)


func main() {

    numberOfJobs := 10

    c := make(chan *exec.Cmd, numberOfJobs)

    for i := 0; i < numberOfJobs; i++ {

        c <- exec.Command("notepad")

    }

    close(c)


    nCPU := runtime.NumCPU()

    var wg sync.WaitGroup

    for i := 0; i < nCPU; i++ {

        wg.Add(1)

        go func() {

            for cmd := range c {

                cmd.Run()

            }

            wg.Done()

        }()

    }


    wg.Wait()

}

这是限制并发的另一种方法:


//using chan to limit the concurrency

package main


import (

    "os/exec"

    "runtime"

    "sync"

)


func main() {

    n := runtime.NumCPU()

    dummy := make(chan bool, n)

    numberOfJobs := 10

    var wg sync.WaitGroup

    for i := 0; i < numberOfJobs; i++ {

        cmd := exec.Command("notepad")

        dummy <- true // wait here if no CPU available

        wg.Add(1)

        go func(cmd *exec.Cmd) {

            //defer func() { <-dummy }()

            cmd.Run()

            wg.Done()

            <-dummy

        }(cmd)

    }

    close(dummy)


    wg.Wait()

}

我希望这有帮助。


查看完整回答
反对 回复 2022-01-10
  • 2 回答
  • 0 关注
  • 175 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信