GO语言goroutine
Posted 两片空白
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GO语言goroutine相关的知识,希望对你有一定的参考价值。
前言
go语言对于并发编程有原生的支持。
如下代码:创建10个协程并发执行。
package main
import (
"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语言中的协程是非抢占式多任务处理,由协程主动交出控制权。
抢占式式多任务处理:操作系统由更高优先级的任务,可以停止当前执行的线程,去执行更高优先级线程。
非抢占式多任务处理:操作系统不能主动去停止。而是由任务主动交出控制权。
线程是抢占式多任务处理,所以等任务切换时,需要内存来保存程序执行的上下文。
协程不需要那麽多内存来保存上下文,只需要保存切换点。
协程是编译器/解释器/虚拟机层面的多任务,不是操作系统层面的多任务。操作系统层面没有协程,
所以协程是轻量级线程。
3. 多个协程可能在一个或者多个线程上执行。
我们知道操作系统有调度器,而go语言也有自己的调度器,来调度协程的运行。所以可能协程在不同的一个或者一个线程上运行。
参数传递给协程的注意点:
代码:
每次开辟的协程参数i需要被传入,如果不传入,会出现越界错误。
因为使用的i在全局只有一份,当i被加到10时,有的协程还没有运行完或者正在运行,此时i时同一个,再执行a[i]时,就越界了,作为参数传入,i会被拷贝一份,每个协程私有。
package main
import (
"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(),显示切换
go语言的协程可能运行在一个线程里,也可能多个协程运行在一个线程里,也有可能多个协程在多个线程里,这由go语言调度器来决定。
以上是关于GO语言goroutine的主要内容,如果未能解决你的问题,请参考以下文章
golang语言并发与并行——goroutine和channel的详细理解