3 回答

TA貢獻(xiàn)1966條經(jīng)驗 獲得超4個贊
當(dāng)您的main()函數(shù)結(jié)束時,您的程序也會結(jié)束。它不會等待其他 goroutine 完成。
引用Go 語言規(guī)范:程序執(zhí)行:
程序執(zhí)行首先初始化主包,然后調(diào)用函數(shù)main。當(dāng)該函數(shù)調(diào)用返回時,程序退出。它不會等待其他(非main)goroutine 完成。
有關(guān)更多詳細(xì)信息,請參閱此答案。
你必須告訴你的main()函數(shù)等待SayHello()作為 goroutine 啟動的函數(shù)完成。您可以將它們與頻道同步,例如:
func SayHello(done chan int) {
for i := 0; i < 10; i++ {
fmt.Print(i, " ")
}
if done != nil {
done <- 0 // Signal that we're done
}
}
func main() {
SayHello(nil) // Passing nil: we don't want notification here
done := make(chan int)
go SayHello(done)
<-done // Wait until done signal arrives
}
另一種選擇是通過關(guān)閉通道來表示完成:
func SayHello(done chan struct{}) {
for i := 0; i < 10; i++ {
fmt.Print(i, " ")
}
if done != nil {
close(done) // Signal that we're done
}
}
func main() {
SayHello(nil) // Passing nil: we don't want notification here
done := make(chan struct{})
go SayHello(done)
<-done // A receive from a closed channel returns the zero value immediately
}
筆記:
根據(jù)您的編輯/評論:如果您希望 2 個正在運(yùn)行的SayHello()函數(shù)隨機(jī)打印“混合”數(shù)字:您不能保證觀察到這種行為。再次,有關(guān)更多詳細(xì)信息,請參閱上述答案。在轉(zhuǎn)到內(nèi)存模型只能保證某些事件發(fā)生的其他事件之前,你有沒有保證2個并發(fā)夠程是如何執(zhí)行的。
您可能會嘗試使用它,但要知道結(jié)果不是確定性的。首先,您必須啟用多個活動 goroutines 才能執(zhí)行:
runtime.GOMAXPROCS(2)
其次,你必須首先SayHello()作為一個 goroutine啟動,因為你當(dāng)前的代碼首先SayHello()在主 goroutine 中執(zhí)行,只有在它完成后才會啟動另一個:
runtime.GOMAXPROCS(2)
done := make(chan struct{})
go SayHello(done) // FIRST START goroutine
SayHello(nil) // And then call SayHello() in the main goroutine
<-done // Wait for completion

TA貢獻(xiàn)1829條經(jīng)驗 獲得超6個贊
或者(對于 icza 的回答)您可以使用WaitGroupfromsync包和匿名函數(shù)來避免更改原始SayHello.
package main
import (
"fmt"
"sync"
)
func SayHello() {
for i := 0; i < 10; i++ {
fmt.Print(i, " ")
}
}
func main() {
SayHello()
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
SayHello()
}()
wg.Wait()
}
為了同時打印數(shù)字,在單獨(dú)的例程中運(yùn)行每個打印語句,如下所示
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(fnScopeI int) {
defer wg.Done()
// next two strings are here just to show routines work simultaneously
amt := time.Duration(rand.Intn(250))
time.Sleep(time.Millisecond * amt)
fmt.Print(fnScopeI, " ")
}(i)
}
wg.Wait()
}

TA貢獻(xiàn)1886條經(jīng)驗 獲得超2個贊
當(dāng)main函數(shù)返回時,Go 程序退出。
一種選擇是使用類似的方法sync.WaitGroup來等待main從main.
另一種方法是調(diào)用runtime.Goexit()在main。從godoc:
Goexit 終止調(diào)用它的 goroutine。沒有其他 goroutine 受到影響。Goexit 在終止 goroutine 之前運(yùn)行所有延遲調(diào)用。因為 Goexit 不是一個恐慌,這些延遲函數(shù)中的任何恢復(fù)調(diào)用都將返回 nil。
從主協(xié)程調(diào)用 Goexit 會終止該協(xié)程,而不會返回 func main。由于 func main 沒有返回,程序繼續(xù)執(zhí)行其他 goroutine。如果所有其他 goroutine 退出,程序就會崩潰。
這允許 main goroutine 停止執(zhí)行,而后臺例程繼續(xù)執(zhí)行。例如:
package main
import (
"fmt"
"runtime"
"time"
)
func f() {
for i := 0; ; i++ {
fmt.Println(i)
time.Sleep(10 * time.Millisecond)
}
}
func main() {
go f()
runtime.Goexit()
}
這比在 main 函數(shù)中永遠(yuǎn)阻塞更干凈,尤其是對于無限的程序。一個缺點是,如果進(jìn)程的所有 goroutine 都返回或退出(包括主 goroutine),Go 會將其檢測為錯誤和恐慌:
fatal error: no goroutines (main called runtime.Goexit) - deadlock!
為了避免這種情況,至少一個 goroutine 必須os.Exit在它返回之前調(diào)用。調(diào)用os.Exit(0)立即終止程序并指示它沒有錯誤地這樣做。例如:
package main
import (
"fmt"
"os"
"runtime"
"time"
)
func f() {
for i := 0; i < 10; i++ {
fmt.Println(i)
time.Sleep(10 * time.Millisecond)
}
os.Exit(0)
}
func main() {
go f()
runtime.Goexit()
}
- 3 回答
- 0 關(guān)注
- 436 瀏覽
添加回答
舉報