Goroutine最佳实践总是考虑Goroutine的退出机制,使用sync.WaitGroup来等待Goroutine完成,避免创建无限制的Goroutine(考虑工作池模式),为Goroutine添加恢复机制(defer + recover)
引言
- 简要介绍Golang的并发模型
- Goroutine和Channel的基本概念
- 为什么需要理解它们的使用时机
第一部分:Goroutine的使用场景
1. 执行独立任务时
// 示例:并发执行多个独立HTTP请求
func fetchURL(url string, wg *sync.WaitGroup){
defer wg.Done()
resp, err := http.Get(url)
if err !=nil{
fmt.Printf("Error fetching %s: %v\n", url, err)
return
}
fmt.Printf("Fetched %s, status: %s\n", url, resp.Status)
}
func main(){
urls :=[]string{"https://golang.org","https://google.com","https://github.com"}
var wg sync.WaitGroup
for_, url :=range urls {
wg.Add(1)
go fetchURL(url,&wg)
}
wg.Wait()
fmt.Println("All requests completed!")
}
2. 需要并行计算时
// 示例:并行计算斐波那契数列
func calculateFibonacci(n int, result chan<-int){
if n <=1{
result <- n
return
}
a :=make(chanint)
b :=make(chanint)
go calculateFibonacci(n-1, a)
go calculateFibonacci(n-2, b)
result <-(<-a +<-b)
}
func main(){
result :=make(chanint)
go calculateFibonacci(10, result)
fmt.Printf("Fib(10) = %d\n",<-result)
}
3. 处理I/O密集型操作时
// 示例:并发读取多个文件
func readFile(filename string, results chan<-string){
data, err := os.ReadFile(filename)
if err !=nil{
results <- fmt.Sprintf("Error reading %s: %v", filename, err)
return
}
results <- fmt.Sprintf("Read %s: %d bytes", filename,len(data))
}
func main(){
files :=[]string{"file1.txt","file2.txt","file3.txt"}
results :=make(chanstring,len(files))
for_, file :=range files {
go readFile(file, results)
}
for range files {
fmt.Println(<-results)
}
}
4. 实现后台任务时
// 示例:后台日志处理器
func logProcessor(logs <-chanstring){
for logEntry :=range logs {
// 模拟处理延迟
time.Sleep(100* time.Millisecond)
fmt.Printf("Processed log: %s\n", logEntry)
}
}
func main(){
logChan :=make(chanstring,100)
go logProcessor(logChan)
// 模拟生成日志
for i :=0; i <10; i++{
logChan <- fmt.Sprintf("Log entry %d", i)
}
close(logChan)
time.Sleep(1* time.Second)// 等待处理完成
}
第二部分:Channel的使用场景
1. Goroutine间通信时
// 示例:生产者-消费者模型
func producer(items chan<-int){
for i :=0; i <5; i++{
items <- i
time.Sleep(time.Second)
}
close(items)
}
func consumer(id int, items <-chanint){
for item :=range items {
fmt.Printf("Consumer %d received: %d\n", id, item)
}
}
func main(){
items :=make(chanint)
go producer(items)
// 启动多个消费者
for i :=1; i <=3; i++{
go consumer(i, items)
}
time.Sleep(6* time.Second)
}
2. 同步Goroutine执行时
// 示例:使用Channel同步多个Goroutine
func worker(id int, ready <-chanstruct{}, done chan<-int){
<-ready // 等待开始信号
fmt.Printf("Worker %d started\n", id)
time.Sleep(time.Duration(rand.Intn(3))* time.Second)
fmt.Printf("Worker %d finished\n", id)
done <- id
}
func main(){
const numWorkers =5
ready :=make(chanstruct{})
done :=make(chanint, numWorkers)
// 启动workers
for i :=1; i <= numWorkers; i++{
go worker(i, ready, done)
}
// 同时开始所有workers
close(ready)
// 等待所有workers完成
for i :=1; i <= numWorkers; i++{
<-done
}
fmt.Println("All workers completed")
}
3. 实现管道模式时
// 示例:数据处理管道
func stage1(in <-chan int)<-chan int{
out :=make(chan int)
go func(){
for n :=range in {
out <- n *2
}
close(out)
}()
return out
}
func stage2(in <-chan int)<-chan int{
out :=make(chan int)
go func(){
for n :=range in {
out <- n +1
}
close(out)
}()
return out
}
func stage3(in <-chan int)<-chan string{
out :=make(chan string)
go func(){
for n :=range in {
out <- fmt.Sprintf("Result: %d", n)
}
close(out)
}()
return out
}
func main(){
// 创建输入channel
in :=make(chanint)
// 构建管道
pipeline :=stage3(stage2(stage1(in)))
// 发送数据
go func(){
for i :=0; i <5; i++{
in <- i
}
close(in)
}()
// 接收结果
for result :=range pipeline {
fmt.Println(result)
}
}
4. 限制并发数量时
// 示例:使用缓冲Channel实现工作池
func worker(id int, jobs <-chan int, results chan<-int){
for j :=range jobs {
fmt.Printf("Worker %d started job %d\n", id, j)
time.Sleep(time.Second)
fmt.Printf("Worker %d finished job %d\n", id, j)
results <- j *2
}
}
func main(){
const numJobs =10
const numWorkers =3
jobs :=make(chanint, numJobs)
results :=make(chanint, numJobs)
// 启动workers
for w :=1; w <= numWorkers; w++{
go worker(w, jobs, results)
}
// 发送jobs
for j :=1; j <= numJobs; j++{
jobs <- j
}
close(jobs)
// 收集结果
for a :=1; a <= numJobs; a++{
<-results
}
}
第三部分:Goroutine和Channel的联合使用
1. 扇出模式
// 示例:一个生产者,多个消费者
func producer(nums chan<-int){
for i :=0; i <10; i++{
nums <- i
}
close(nums)
}
func consumer(id int, nums <-chan int, done chan<-bool){
for num :=range nums {
fmt.Printf("Consumer %d got %d\n", id, num)
time.Sleep(time.Duration(rand.Intn(500))* time.Millisecond)
}
done <-true
}
func main(){
nums :=make(chanint)
done :=make(chanbool)
go producer(nums)
// 启动多个消费者
for i :=0; i <3; i++{
go consumer(i, nums, done)
}
// 等待所有消费者完成
for i :=0; i <3; i++{
<-done
}
}
2. 扇入模式
// 示例:多个生产者,一个消费者
func producer(id int, nums chan<-int){
for i :=0; i <3; i++{
nums <- id*10+ i
time.Sleep(time.Duration(rand.Intn(500))* time.Millisecond)
}
}
func consumer(nums <-chanint, done chan<-bool){
for num :=range nums {
fmt.Printf("Received: %d\n", num)
}
done <-true
}
func main(){
nums :=make(chanint)
done :=make(chanbool)
// 启动多个生产者
for i :=0; i <3; i++{
go producer(i, nums)
}
// 启动消费者
go func(){
time.Sleep(2* time.Second)
close(nums)
}()
go consumer(nums, done)
<-done
}
3. 超时控制
// 示例:使用select实现超时控制
func longRunningTask(result chan<-string){
// 模拟长时间运行的任务
time.Sleep(3* time.Second)
result <-"Task completed"
}
func main(){
result :=make(chanstring)
go longRunningTask(result)
select{
case res :=<-result:
fmt.Println(res)
case<-time.After(2* time.Second):
fmt.Println("Task timed out")
}
}
第四部分:最佳实践与常见陷阱
Goroutine最佳实践
- 总是考虑Goroutine的退出机制
- 使用sync.WaitGroup来等待Goroutine完成
- 避免创建无限制的Goroutine(考虑工作池模式)
- 为Goroutine添加恢复机制(defer + recover)
Channel最佳实践
- 明确Channel的所有权(哪个Goroutine负责关闭)
- 使用缓冲Channel来解耦生产者和消费者
- 考虑使用context.Context来取消Channel操作
- 小心nil Channel和已关闭Channel的操作
常见陷阱
- Goroutine泄漏
- Channel死锁
- 共享内存竞争条件
- 不正确的Channel关闭
结论
- 总结Goroutine和Channel的核心使用场景
- 强调根据具体需求选择合适的并发模式
- 推荐进一步学习资源(官方文档、经典书籍等)
AI大模型学习福利
作为一名热心肠的互联网老兵,我决定把宝贵的AI知识分享给大家。 至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
一、全套AGI大模型学习路线
AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获取
二、640套AI大模型报告合集
这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获
三、AI大模型经典PDF籍
随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获
四、AI大模型商业化落地方案

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获
作为普通人,入局大模型时代需要持续学习和实践,不断提高自己的技能和认知水平,同时也需要有责任感和伦理意识,为人工智能的健康发展贡献力量
Golang并发模型详解

被折叠的 条评论
为什么被折叠?



