SayHello()按预期执行时,goroutine不打印任何内容。

package main

import "fmt"

func SayHello() {
    for i := 0; i < 10 ; i++ {
        fmt.Print(i, " ")
    }
}

func main() {
    SayHello()
    go SayHello()
}


评论

如果时间不执行,可能不会执行Goroutine的重复。包括睡眠

#1 楼

main()函数结束时,程序也将结束。它不等待其他goroutine完成。

从Go语言规范中引用:程序执行:


程序执行从初始化主程序包开始,然后调用功能main。当该函数调用返回时,程序退出。它不等待其他(非main)例程完成。


有关更多详细信息,请参见此答案。等待作为goroutine启动的main()函数完成。您可以将它们与通道同步,例如:

func SayHello(done chan int) {
    for i := 0; i < 10; i++ {
        fmt.Print(i, " ")
    }
    if done != nil {
        done <- 0 // Signal that we're done
    }
}

func main() {
    SayHello(nil) // Passing nil: we don't want notification here
    done := make(chan int)
    go SayHello(done)
    <-done // Wait until done signal arrives
}


另一种选择是通过关闭通道来表示完成信号: >
注释:

根据您的编辑/注释:如果要让2个正在运行的SayHello()函数随机打印“混合”数字:您不能保证观察到这种行为。同样,请参阅上述答案以获取更多详细信息。 Go Memory Model仅保证某些事件先于其他事件发生,而不能保证如何执行2个并发goroutine。

您可以尝试使用它,但是知道结果不会是确定的。首先,您必须启用多个活动goroutine才能执行:主goroutine,只有完成后才启动另一个goroutine:

func SayHello(done chan struct{}) {
    for i := 0; i < 10; i++ {
        fmt.Print(i, " ")
    }
    if done != nil {
        close(done) // Signal that we're done
    }
}

func main() {
    SayHello(nil) // Passing nil: we don't want notification here
    done := make(chan struct{})
    go SayHello(done)
    <-done // A receive from a closed channel returns the zero value immediately
}


评论


是的,我在阅读dave.cheney.net/2014/03/19/channel-axioms后才了解您的编辑:A永远发送到nil通道块,A永远接收nil通道块。

–VonC
2015年3月10日在7:40

@DineshPanchananam您所说的“无序”时尚是什么意思?您希望从运行的2个SayHello()函数中随机看到混合数吗?

–icza
15年3月10日在8:03

@DineshPanchananam我编辑了我的答案以解决这种情况。简而言之,您不能保证观察到这种行为(即使您这样做,也不是确定性的)。

–icza
2015年3月10日在8:28

#2 楼

另一种方法(以icza的回答),您可以使用WaitGroup软件包中的sync和匿名函数来避免更改原始SayHello。像下面这样的单独例程

package main

import (
    "fmt"
    "sync"
)

func SayHello() {
    for i := 0; i < 10; i++ {
        fmt.Print(i, " ")
    }
}

func main() {
    SayHello()

    var wg sync.WaitGroup
    wg.Add(1)

    go func() {
        defer wg.Done()
        SayHello()
    }()

    wg.Wait()
}


评论


@DineshPanchananam是否要在单独的例程中打印每个数字?

– Sundrique
2015年3月10日在8:05

不,我期望有“平行”的意思,但是我认为我错了。

–Dinesh Panchananam
2015年3月10日在8:10

@DineshPanchananam检查答案的第二部分

– Sundrique
2015年3月10日在8:21

另外,在只有一个函数调用时(第一个代码示例),请不要使用defer-在函数调用之后将wg.Done()移至即可。在这种情况下,无需使用延迟。

– ttacon
2015年3月10日14:14

#3 楼

main函数返回时,Go程序退出。在godoc中:

Goexit终止调用它的goroutine。没有其他goroutine受到影响。 Goexit在终止goroutine之前运行所有延迟的调用。由于Goexit不会发生紧急情况,因此这些延迟函数中的任何恢复调用都将返回nil。
从主goroutine调用Goexit将终止该goroutine,而不会返回func main。由于func main尚未返回,因此程序将继续执行其他goroutine。如果所有其他goroutine都退出,则程序将崩溃。

这允许主goroutine在后台例程继续执行的同时停止执行。例如:
package main

import (
    "fmt"
    "runtime"
    "time"
)

func f() {
    for i := 0; ; i++ {
        fmt.Println(i)
        time.Sleep(10 * time.Millisecond)
    }
}

func main() {
    go f()
    runtime.Goexit()
}

这比永久阻塞主函数更干净,尤其是对于无限程序。缺点是,如果某个进程的所有goroutine都返回或退出(包括主goroutine),则Go会将其检测为错误并感到恐慌:在返回之前,请致电sync.WaitGroup。调用main立即终止程序,并指示它这样做没有错误。例如:
fatal error: no goroutines (main called runtime.Goexit) - deadlock!