前言 go语言对于并发编程有原生的支持。
如下代码:创建10个协程并发执行。
package mainimport (
"fmt"
"time"
)func main() {
for i := 0;
i < 10;
i++ {
go func(i int) {
fmt.Printf("hello from goroutine %d\n", i)
}(i)
}
//main函数执行完,协程也会被终止,等待1秒,协程执行完
time.Sleep(time.Second)
}
Courotine 协程: 1. go语言中开辟的实际是协程,协程是轻量级线程。作用和线程差不多,并发执行任务。
在go语言中可以开辟很多协程,比如:1000个协程,但是开辟1000个线程消耗的资源就比较多了。
2. 协程为什么是轻量级线程。
go语言中的协程是非抢占式多任务处理,由协程主动交出控制权。
抢占式式多任务处理:操作系统由更高优先级的任务,可以停止当前执行的线程,去执行更高优先级线程。线程是抢占式多任务处理,所以等任务切换时,需要内存来保存程序执行的上下文。
非抢占式多任务处理:操作系统不能主动去停止。而是由任务主动交出控制权。
协程不需要那麽多内存来保存上下文,只需要保存切换点。
协程是编译器/解释器/虚拟机层面的多任务,不是操作系统层面的多任务。操作系统层面没有协程,
所以协程是轻量级线程。
【golang|GO语言goroutine】3. 多个协程可能在一个或者多个线程上执行。
我们知道操作系统有调度器,而go语言也有自己的调度器,来调度协程的运行。所以可能协程在不同的一个或者一个线程上运行。
参数传递给协程的注意点:
代码:
每次开辟的协程参数i需要被传入,如果不传入,会出现越界错误。
因为使用的i在全局只有一份,当i被加到10时,有的协程还没有运行完或者正在运行,此时i时同一个,再执行a[i]时,就越界了,作为参数传入,i会被拷贝一份,每个协程私有。
package mainimport (
"fmt"
"time"
)func main() {
var a [10]int
for i := 0;
i < 10;
i++ {
go func(i int) {
for {
a[i]++
}
}(i)
// 会吹按越界错误
// go func() {
//for {
//a[i]++
//}
// }()
}
//main函数执行完,协程也会被终止,等待1秒,协程执行完
time.Sleep(time.Second)
fmt.Println(a)
}
可以在命令行中可以输入go run -race xxx, 查看访问冲突。
文章图片
go语言的调度器 子程序(普通函数)是协程的特例。
文章图片
- 任何函数前加上go关键字,就能送给调度器调度,
- 虽然协程是非抢占式的,但是为了提高效率,调度器会在合适的点进行切换,不需要显示去切换。
- I/O操作,Select
- channel
- 等待锁
- 函数调用(有时)
- runtime.Gosched(),显示切换
文章图片
推荐阅读
- 七天实现web框架--上下文建立
- 七天实现web框架--路由映射
- go语言学习——函数,方法与接口
- CSS :lang选择器用法示例
- 【Go进阶—基础特性】panic 和 recover
- go语言学习——匿名函数
- go-错误与异常
- GoGo|kubebuilder 上手体验
- linux|ubuntu20.04安装微信和QQ,腾讯会议,以及一些其他实用软件