【Go】Go语言并发编程

1. 普通 goroutine 示例

此部分展示了如何在主函数中启动一个子协程,并说明了如何查询与设置逻辑处理器(P)的数量(代码中被注释掉)。

go 复制代码
// 普通 goroutine 示例
package main

import (
	"fmt"
	"time"
	// "runtime"  // 如果需要查询或设置 GOMAXPROCS,可引入 runtime 包
)

func hello() {
	fmt.Println("hello goroutine")
}

func main() {
	fmt.Println("hello world!")

	// GOMAXPROCS 示例:
	// 查询当前设置的 P 数量(传入 0)
	// fmt.Println(runtime.GOMAXPROCS(0))
	// 设置 P 数量为 8
	// fmt.Println(runtime.GOMAXPROCS(8))
	// 再次查询当前设置的 P 数量
	// fmt.Println(runtime.GOMAXPROCS(0))

	// 启动一个子协程执行 hello 函数
	go hello()

	// 主协程休眠 1 秒,保证子协程有机会输出
	time.Sleep(1 * time.Second)
}

知识点说明

  • goroutine 创建 :使用 go 关键字调用函数 hello() 来创建一个新的协程。
  • GOMAXPROCS :可以通过 runtime.GOMAXPROCS 来查询或设置程序并发运行的 P 数量,默认为 CPU 核心数(此处代码示例中以注释形式展示)。

2. 匿名 goroutine 示例

使用匿名函数直接创建 goroutine,展示子协程与主协程同时执行的情况。

go 复制代码
// 匿名 goroutine 示例
package main

import (
	"fmt"
	"time"
)

func main() {
	// 启动一个匿名 goroutine,不断打印子协程的计数,每秒一次
	go func() {
		i := 0
		for {
			i++
			fmt.Println("子协程 i =", i)
			time.Sleep(1 * time.Second)
		}
	}()

	// 主协程循环 3 次打印自己的计数,每次间隔 1 秒
	for i := 0; i < 3; i++ {
		fmt.Println("主协程 i =", i)
		time.Sleep(1 * time.Second)
	}
}

知识点说明

  • 匿名 goroutine :直接在 go 后面写匿名函数,适用于简单逻辑或无需复用的协程代码。
  • 并发执行:子协程与主协程各自独立运行,主协程通过循环和休眠展示执行过程。

3. 协程异常处理 ------ except_test

通过 deferrecover() 捕获异常,防止单个协程 panic 导致整个程序退出。

go 复制代码
// 协程异常处理示例1:捕获 panic
package main

import (
	"fmt"
)

func except_test() {
	// 使用 defer + recover 捕获 panic
	defer func() {
		if r := recover(); r != nil {
			fmt.Println("程序发生异常!", r)
		}
	}()
	fmt.Println("this is except_test")

	// 故意制造数组越界异常
	lst := []int{1, 2, 3}
	fmt.Println(lst[3]) // 索引越界,会引发 panic
}

知识点说明

  • 异常捕获机制 :在函数开始使用 defer 定义匿名函数,并调用 recover() 捕获 panic,从而避免未捕获异常导致整个程序崩溃。
  • 故意制造异常 :通过访问越界索引 lst[3] 来触发 panic。

4. 协程异常处理 ------ except_test2

简单示例,展示协程中执行正常任务并通过休眠模拟处理耗时任务。

go 复制代码
// 协程异常处理示例2:正常执行的协程
package main

import (
	"fmt"
	"time"
)

func except_test2() {
	fmt.Println("this is except_test2")
	time.Sleep(1 * time.Second)
	fmt.Println("this is except_test2 end .....")
}

知识点说明

  • 正常流程:该函数仅展示普通执行流程,没有异常发生,主要用于与异常处理的协程进行对比。

5. 主函数 main

main 函数中同时启动两个协程,一个负责异常测试(会因数组越界引发 panic,但已被捕获),另一个执行正常任务。最后通过休眠确保子协程有足够时间运行。

go 复制代码
// 主函数:启动两个协程,观察异常处理效果
package main

import (
	"fmt"
	"time"
)

func except_test() {
	defer func() {
		if r := recover(); r != nil {
			fmt.Println("程序发生异常!", r)
		}
	}()
	fmt.Println("this is except_test")
	lst := []int{1, 2, 3}
	fmt.Println(lst[3])
}

func except_test2() {
	fmt.Println("this is except_test2")
	time.Sleep(1 * time.Second)
	fmt.Println("this is except_test2 end .....")
}

func main() {
	fmt.Println("this is main")
	// 启动两个协程
	go except_test()
	go except_test2()
	
	// 主协程休眠 2 秒,确保子协程执行完成
	time.Sleep(2 * time.Second)
	fmt.Println("end....")
}

知识点说明

  • 协程并发 :同时启动两个协程,一个处理异常(except_test),一个正常执行(except_test2)。
  • 主协程等待 :使用 time.Sleep(2 * time.Second) 让主协程等待,保证子协程输出可见。
  • 整体流程:先打印 "this is main",然后分别运行两个协程,最终在主协程结束前打印 "end..."。
相关推荐
Blossom.1186 分钟前
基于Python的机器学习入门指南
开发语言·人工智能·经验分享·python·其他·机器学习·个人开发
郝YH是人间理想1 小时前
Python面向对象
开发语言·python·面向对象
大土豆的bug记录3 小时前
鸿蒙进行视频上传,使用 request.uploadFile方法
开发语言·前端·华为·arkts·鸿蒙·arkui
hhw1991125 小时前
c#知识点补充3
开发语言·c#
Antonio9155 小时前
【Q&A】观察者模式在QT有哪些应用?
开发语言·qt·观察者模式
Pandaconda5 小时前
【后端开发面试题】每日 3 题(二十)
开发语言·分布式·后端·面试·消息队列·熔断·服务限流
mqwguardain5 小时前
python常见反爬思路详解
开发语言·python
lmy3477712326 小时前
东软鸿蒙C++开发面经
开发语言·c++
hakesashou6 小时前
python多线程和多进程的区别有哪些
java·开发语言·jvm
每次的天空6 小时前
项目总结:GetX + Kotlin 协程实现跨端音乐播放实时同步
android·开发语言·kotlin