上卷 程序设计
中卷 标准库
- bufio 1.18
- bytes 1.18
- io 1.18
- container 1.18
- encoding 1.18
- crypto 1.18
- hash 1.18
- index 1.18
- sort 1.18
- context 1.18
- database 1.18
- connection
- query
- queryrow
- exec
- prepare
- transaction
- scan & null
- context
- tcp
- udp
- http
- server
- handler
- client
- h2、tls
- url
- rpc
- exec
- signal
- embed 1.18
- plugin 1.18
- reflect 1.18
- runtime 1.18
- KeepAlived
- ReadMemStats
- SetFinalizer
- Stack
- sync 1.18
- atomic
- mutex
- rwmutex
- waitgroup
- cond
- once
- map
- pool
- copycheck
- nocopy
- unsafe 1.18
- fmt 1.18
- log 1.18
- math 1.18
- time 1.18
- timer
下卷 运行时
源码剖析
附录
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
9.1.1 结束
所有用户代码都以 goroutine 执行,包括 main.main
入口函数。
进程结束,不会等待其他正在执行或尚未执行的任务。
func main() { go func() { defer println("g done.") time.Sleep(time.Second) }() defer println("main done.") } // main done.
等待
等待任务结束,可以做得比 time.Sleep
更优雅一些。
channel
: 信号通知。WaitGroup
:等待多个任务结束。Context
:上下文通知。Mutex
:锁阻塞。
如果只是一次性通知行为,可使用空结构。只要关闭通道,等待(阻塞)即可解除。
func main() { q := make(chan struct{}) go func() { defer close(q) println("done.") }() <- q }
添加计数( WaitGroup.Add
)应在创建任务和等待之前,否则可能导致等待提前解除。
可以有多处等待,实现群体性通知。
func main() { var wg sync.WaitGroup wg.Add(10) for i := 0; i < 10; i++ { go func(id int) { defer wg.Done() println(id, "done.") }(i) } wg.Wait() }
func main() { var wg sync.WaitGroup for i := 0; i < 10; i++ { // 可写在此处,应对未知循环数。 // 但不可放在下面 goroutine 函数内, // 因为它可能未执行,下面 Wait 先结束了。 wg.Add(1) go func(id int) { defer wg.Done() println(id, "done.") }(i) } wg.Wait() }
上下文的实现和通道基本一致。
func main() { ctx, cancel := context.WithCancel(context.Background()) go func() { defer cancel() println("done.") }() <- ctx.Done() }
利用锁实现 “同步”,在其他语言很常见,但 Go 更倾向于以通信代替。
func main() { var lock sync.Mutex lock.Lock() go func() { defer lock.Unlock() println("done.") }() lock.Lock() lock.Unlock() println("exit") }
终止
主动结束任务,有以下几种方式。
- 调用
runtime.Goexit
终止任务。 - 调用
os.Exit
结束进程。
在任务调用堆栈(call stack)的任何位置调用 runtime.Goexit
都能立即终止任务。
结束前,延迟调用(defer)被执行。其他任务不受影响。
func main() { q := make(chan struct{}) go func() { defer close(q) defer println("done.") // 如果将 b 里面的 Goexit 换成 return, // 那只是结束了 b(),而非整个调用堆栈。 a() b() c() }() <- q } func a() { println("a") } func b() { println("b"); runtime.Goexit() } func c() { println("c") } // a // b // done.
在 main goroutine
里调用 Goexit
,它会等待其他任务结束,然后崩溃进程。
func main() { q := make(chan struct{}) go func() { defer close(q) defer println("done.") time.Sleep(time.Second) }() runtime.Goexit() <- q } // done. // fatal error: no goroutines (main called runtime.Goexit) - deadlock!
而 os.Exit
可在任意位置结束进程。不等待其他任务,也不执行延迟调用。
func main() { go func() { defer println("g done.") time.Sleep(time.Second) }() defer println("main done.") os.Exit(-1) }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论