1 回答
TA贡献1811条经验 获得超5个赞
每个函数都是从 goroutine 调用的,甚至是main()
函数(称为 goroutine main
)。
Go 中的 goroutine 没有身份。哪个 goroutine 调用函数并不重要。
回答你的“原始”问题:
有什么方法可以查明正在运行的函数是否被调用为 goroutine 吗?
如果我们将 this 定义为使用该go
语句或不使用该语句调用的函数,那么答案是肯定的:我们可以检查这一点。
但在此之前:我不会将此信息用于任何用途。不要编写依赖于此的代码,也不要编写依赖于哪个 goroutine 调用函数的代码。如果需要从多个 goroutine 同时访问资源,只需使用适当的同步即可。
基本上我们可以检查调用堆栈:相互调用的函数列表。如果该函数位于该列表的顶部,则使用它来调用它go
(检查答案末尾的注释)。如果调用堆栈中在该函数之前还有其他函数,则从go
另一个函数(位于调用堆栈中之前的函数)调用该函数,而无需使用 , 。
我们可以用来runtime.Callers()
获取调用 goroutine 的堆栈。这是我们检查是否有其他函数调用“us”的方法:
func f(name string) {
count := runtime.Callers(3, make([]uintptr, 1))
if count == 0 {
fmt.Printf("%q is launched as new\n", name)
}
}
测试它:
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) }
这将输出(在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
注意:基本上所有调用堆栈的“顶部”都有一个runtime.goexit()
函数,这是在 goroutine 上运行的最顶层函数,也是所有 goroutine 的“退出”点。这就是为什么我们从堆栈中跳过 3 帧(0. 是runtime.Callers()
它本身,1. 是f()
函数,最后一个要跳过的帧是runtime.goexit()
)。您可以在此Go Playground中检查包含函数和文件名+行号的完整调用堆栈。这不会改变这个解决方案的可行性,只是我们必须跳过 3 帧而不是 2 帧来判断是f()
从另一个函数调用还是通过go
语句调用。
- 1 回答
- 0 关注
- 111 浏览
添加回答
举报