Вопрос

Given this playground:

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")
}

Why is the output:

oneFunc

and "anotherFunc" is never printed?

Это было полезно?

Решение

anotherFunc doesn't execute until oneFunc returns a value. Because of this, the program exits before anotherFunc is able to run. You need to wait for anotherFunc to run before main exits.

You can do this via Go channels. For Example:

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
}

Другие советы

The way that I like to about it is this, go – like defer – consumes the last invocation, or pair parentheses, on the line and will invoke that function out of order. Every invocation before that is synchronous.

Where go makes the invocation concurrent. And defer delays invocation until current function returns.

There is a really good example of this in the defer section of Effective Go

The expression behind the go keyword is evaluated and the function value of that expression is then executed concurrently.

So, in your example oneFunc() is called, hence the oneFunc output, and the method anotherFunc on the returned instance is called concurrently. However, your program terminates before the goroutine can run which is why you don't see anotherFunc printed.

Solution: Use sync.WaitGroup or channels for synchronization.

To actually (empirically) verify that your go call executes anotherFunc concurrently and not oneFunc you can print the stack in each function and compare the output. Example (on play):

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")
}

You will see something like this:

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

The stack trace even tells you that the two functions are running in different goroutines, no comparison of method calls needed.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top