
在Go中,test()是同步阻塞调用,立即执行并等待返回;而go test()则启动一个独立的goroutine异步执行,不阻塞当前流程,需显式同步机制才能确保其完成。
在go中,`test()`是同步阻塞调用,立即执行并等待返回;而`go test()`则启动一个独立的goroutine异步执行,不阻塞当前流程,需显式同步机制才能确保其完成。
Go语言通过go关键字提供轻量级并发支持——它不是简单的“后台运行”,而是启动一个goroutine,即由Go运行时管理的、可被调度的独立执行单元。理解test()与go test()的区别,本质是理解同步执行与并发执行的差异。
同步调用:test()
- 当前goroutine(如
main)暂停执行,跳转至test函数体; -
test执行完毕后,控制权才返回调用点; - 整个过程是确定性、顺序的,适合依赖执行结果的场景。
异步启动:go test()
- 立即返回,不等待
test执行; -
test在新goroutine中并发运行,与调用者解耦; - 若主goroutine(如
main)退出,整个程序终止——所有其他goroutine将被强制结束,无论是否完成。
例如:
package main
import (
"fmt"
"time"
)
func test(msg string) {
fmt.Printf("hello %s\n", msg)
time.Sleep(100 * time.Millisecond) // 模拟耗时操作
}
func main() {
test("bob") // 同步:立即输出 "hello bob"
go test("sue") // 异步:启动goroutine,但main几乎立刻结束
// ⚠️ 此处无同步机制 → "hello sue" 极大概率不会打印!
}运行上述代码,通常仅输出hello bob,因为main函数在go test("sue")启动后迅速退出,导致程序终止,sue对应的goroutine被回收。
如何正确等待goroutine完成?
不能依赖time.Sleep(不可靠、不精确),推荐使用通道(channel) 或 sync.WaitGroup:
立即学习“go语言免费学习笔记(深入)”;
✅ 推荐方式:使用 sync.WaitGroup
package main
import (
"fmt"
"sync"
"time"
)
func test(msg string, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("hello %s\n", msg)
time.Sleep(100 * time.Millisecond)
}
func main() {
var wg sync.WaitGroup
wg.Add(1)
go test("sue", &wg)
test("bob") // 同步执行
wg.Wait() // 阻塞直到所有Add的goroutine完成
fmt.Println("all done")
}✅ 通道方式(适用于需要传递结果的场景):
func main() {
done := make(chan bool)
go func() {
test("sue")
done <- true
}()
test("bob")
<-done // 等待goroutine发送信号
}注意事项
-
go启动的函数必须是可调用的(函数值、方法、匿名函数等),不能是语句(如go x++非法); - goroutine间不共享栈,但可通过共享内存(如全局变量)或通信(channel)协作;
- 过度滥用
go而不同步,易导致竞态、资源泄漏或静默失败——务必明确生命周期管理。
掌握go关键字的语义,是写出健壮、可维护Go并发程序的第一步:启动不等于保证执行,异步不等于无序,goroutine需同步,方得始终。


















