
线程阻塞的几种方法
1. 使用信号量 (Signal) 监听 (Go语言中最常见)
这是 Go 程序中等待程序结束的标准做法。
go
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
ticker := time.NewTicker(3 * time.Second)
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
go func() {
for t := range ticker.C {
fmt.Printf("now: %v\n", t)
}
}()
<-stop // 等待中断信号
fmt.Println("\n程序即将退出")
ticker.Stop()
}
优点:可以优雅地处理 Ctrl+C (SIGINT
) 或系统终止信号 (SIGTERM
)。
2. 使用 sync.WaitGroup
当你有多个 goroutine 在运行时,可以用 WaitGroup
等待它们完成。
go
package main
import (
"fmt"
"sync"
"time"
)
func worker(wg *sync.WaitGroup) {
defer wg.Done()
time.Sleep(2 * time.Second)
fmt.Println("工作完成")
}
func main() {
var wg sync.WaitGroup
wg.Add(2)
go worker(&wg)
go worker(&wg)
// 等待所有 goroutine 完成
wg.Wait()
fmt.Println("所有任务完成,主线程退出")
}
3. 使用 time.Sleep()
(仅用于测试)
适用于简单的测试场景,不推荐用于生产环境。
go
package main
import "time"
func main() {
go func() {
// 模拟后台任务
for {
// do something
time.Sleep(1 * time.Second)
}
}()
// 让主线程休眠足够长时间
time.Sleep(1000 * time.Hour)
}
4. 使用 chan struct{}
阻塞
创建一个无缓冲通道并永远阻塞在接收操作上。
go
package main
func main() {
done := make(chan struct{})
go func() {
// 做一些事情...
// 当需要退出时,可以发送信号:done <- struct{}{}
}()
// 主线程阻塞在这里
<-done
}
5. select {}
永久阻塞,不消耗资源,最佳实践
go
package main
import (
"fmt"
"time"
)
func main() {
ticker := time.NewTicker(3 * time.Second)
go func() {
//ticker.C就是当前执行的时间
for t := range ticker.C {
fmt.Printf("now: %v\n", t)
}
}()
select {}
}