Check if function is being called as goroutine or not

我与影子孤独终老i 提交于 2021-01-28 10:56:25

问题


Is there any way to find out if a running function was called as goroutine or not?

I've read 'go tour' and I am interested in building a websocket server with golang, so I found this tutorial https://tutorialedge.net/golang/go-websocket-tutorial/

Now I'm wondering if wsEndpoint function from the tutorial is invoked as goroutine (e.g. go wsEndpoint(...)) or not.

I've tried to read http package documentation, but did not get clear picture, just a guess that the handler will be called with go routine. Is that true?


回答1:


Every function is called from a goroutine, even the main() function (which is called the main goroutine).

And goroutines in Go have no identity. It does not matter which goroutine calls a function.

To answer your "original" question:

Is there any way to find out if a running function was called as goroutine or not?

If we define this as the function being called with the go statement or without that, then the answer is yes: we can check that.

But before we do: I would not use this information for anything. Don't write code that depends on this, nor on which goroutine calls a function. If you need to access a resource concurrently from multiple goroutines, just use proper synchronization.

Basically we can check the call stack: the list of functions that call each other. If the function is at the top of that list, then it was called using go (check note at the end of the answer). If there are other functions before that in the call stack, then it was called without go, from another function (that places before in the call stack).

We may use runtime.Callers() to get the calling goroutine's stack. This is how we can check if there are other functions calling "us":

func f(name string) {
    count := runtime.Callers(3, make([]uintptr, 1))
    if count == 0 {
        fmt.Printf("%q is launched as new\n", name)
    }
}

Testing it:

func main() {
    f("normal")
    go f("with-go")

    func() { f("from-anon") }()
    func() { go f("from-anon-with-go") }()

    f2("from-f2")
    go f2("with-go-from-f2")

    f3("from-f3")
    go f3("with-go-from-f3")

    time.Sleep(time.Second)
}

func f2(name string) { f(name) }
func f3(name string) { go f(name) }

This will output (try it on the Go Playground):

"with-go" is launched as new
"from-anon-with-go" is launched as new
"from-f3" is launched as new
"with-go-from-f3" is launched as new

Note: basically there is a runtime.goexit() function on "top" of all call stacks, this is the top-most function running on a goroutine and is the "exit" point for all goroutines. This is why we skip 3 frames from the stack (0. is runtime.Callers() itself, 1. is the f() function, and the last one to skip is runtime.goexit()). You can check the full call stacks with function and file names+line numbers in this Go Playground. This doesn't change the viability of this solution, it's just that we have to skip 3 frames instead of 2 to tell if f() was called from another function or with the go statement.



来源:https://stackoverflow.com/questions/56702183/check-if-function-is-being-called-as-goroutine-or-not

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!