简体   繁体   English

链接函数如何作为goroutines执行?

[英]How do chained functions get executed as goroutines?

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 oneFunc

and "anotherFunc" is never printed? 并且“anotherFunc”从未打印过?

anotherFunc doesn't execute until oneFunc returns a value. anotherFunc不执行,直到oneFunc返回一个值。 Because of this, the program exits before anotherFunc is able to run. 因此,程序在anotherFunc能够运行之前退出。 You need to wait for anotherFunc to run before main exits. 您需要等待anotherFuncmain退出之前运行。

You can do this via Go channels. 您可以通过Go频道完成此操作。 For Example: 例如:

http://play.golang.org/p/dWoLB9afSj 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 expression behind the go keyword is evaluated and the function value of that expression is then executed concurrently. 评估go关键字后面的表达式,然后同时执行该表达式的函数值。

So, in your example oneFunc() is called, hence the oneFunc output, and the method anotherFunc on the returned instance is called concurrently. 因此,在您的示例中, oneFunc() ,因此oneFunc输出,并且返回实例上的方法anotherFunc被并发调用。 However, your program terminates before the goroutine can run which is why you don't see anotherFunc printed. 但是,您的程序会在goroutine运行之前终止,这就是您没有看到打印了anotherFunc

Solution: Use sync.WaitGroup or channels for synchronization. 解决方案:使用sync.WaitGroup或通道进行同步。

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. 要实际(凭经验)验证您的go调用同时执行anotherFunc不是 oneFunc您可以在每个函数中打印堆栈并比较输出。 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. 堆栈跟踪甚至告诉您这两个函数在不同的goroutine中运行,不需要比较方法调用。

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 . 我喜欢它的方式就是这样, go -like defer - 在行上消耗最后一次调用或对括号,并且将不按顺序调用该函数。 Every invocation before that is synchronous. 之前的每次调用都是同步的。

Where go makes the invocation concurrent. go使得调用并发。 And defer delays invocation until current function returns. defer延迟调用,直到当前函数返回。

There is a really good example of this in the defer section of Effective Go Effective Godefer部分中有一个非常好的例子

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM