3

鉴于这个游乐场

package main

import "fmt"

func main() {
    go oneFunc().anotherFunc()
}

func oneFunc() something {
    fmt.Println("oneFunc")
    return something{}
}

type something struct{}

func (s something) anotherFunc() {
    fmt.Println("anotherFunc")
}

为什么输出:

oneFunc

并且“anotherFunc”永远不会打印?

4

3 回答 3

5

anotherFunconeFunc在返回值之前不会执行。正因为如此,程序退出之前anotherFunc才能够运行。您需要等待anotherFunc运行才能main退出。

您可以通过 Go 频道执行此操作。例如:

http://play.golang.org/p/dWoLB9afSj

package main

import "fmt"

func main() {
    ch := make(chan int)
    go oneFunc(ch).anotherFunc()
    fmt.Println("Waiting...")
    <-ch
    fmt.Println("Done.")
}

func oneFunc(ch chan int) something {
    fmt.Println("oneFunc")
    return something{ch}
}

type something struct{
    ch chan int
}

func (s something) anotherFunc() {
    fmt.Println("anotherFunc")
    s.ch <- 1
}
于 2013-11-05T22:42:15.767 回答
2

计算关键字后面的go表达式,然后同时执行该表达式的函数值。

因此,在您的示例oneFunc()中被调用,因此oneFunc输出,并且anotherFunc返回实例上的方法被同时调用。但是,您的程序在 goroutine 可以运行之前终止,这就是您看不到anotherFunc打印的原因。

解决方法:使用sync.WaitGroup或通道进行同步。

要实际(凭经验)验证您的go调用是否anotherFunc同时执行,而不是 oneFunc您可以在每个函数中打印堆栈并比较输出。示例(播放中):

var wg = sync.WaitGroup{}

func main() {
    wg.Add(1)
    go oneFunc().anotherFunc()
    wg.Wait()
}

func oneFunc() something {
    fmt.Println("oneFunc")

    buf := make([]byte, 4096)
    runtime.Stack(buf, false)
    fmt.Println("Stack of oneFunc:", string(buf))

    return something{}
}

type something struct{}

func (s something) anotherFunc() {
    defer wg.Done()

    buf := make([]byte, 4096)
    runtime.Stack(buf, false)
    fmt.Println("Stack of anotherFunc:", string(buf))

    fmt.Println("anotherFunc")
}

你会看到这样的东西:

oneFunc
Stack of oneFunc: goroutine 1 [running]:
main.oneFunc()
    /tmpfs/gosandbox-342f581d_b6e8aa8b_334a0f88_c8221b7e_20882985/prog.go:20 +0x118
main.main()
    /tmpfs/gosandbox-342f581d_b6e8aa8b_334a0f88_c8221b7e_20882985/prog.go:11 +0x50

Stack of anotherFunc: goroutine 2 [running]:
main.something.anotherFunc()
    /tmpfs/gosandbox-342f581d_b6e8aa8b_334a0f88_c8221b7e_20882985/prog.go:32 +0xb2
created by main.main
    /tmpfs/gosandbox-342f581d_b6e8aa8b_334a0f88_c8221b7e_20882985/prog.go:11 +0x69

anotherFunc

堆栈跟踪甚至告诉您这两个函数在不同的 goroutine 中运行,无需比较方法调用。

于 2013-11-05T23:10:30.980 回答
2

我喜欢的方式是,go——比如defer——消耗最后一次调用,或者成对的括号,在行上并且会乱序调用那个函数。在此之前的每次调用都是同步的。

Wherego使调用并发。并defer延迟调用直到当前函数返回。

在Effective Godefer部分有一个很好的例子

于 2013-11-05T23:46:54.873 回答