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 關注
- 140 瀏覽
添加回答
舉報