Goroutine
一、并发
并发编程表现为程序有若干个自主的活动单元组成,在今天的互联网中,一个web服务器可能一次处理上千个请求,而平板电脑和手机在渲染用户界面的同时,后端还同步进行着计算和处理网络请求等。
在go语言中每一个并发执行的活动称之为goroutine,而在我们最常见的main函数中其实也是一个goroutine(主goroutine),在此之前,我们所见的介绍语法或者程序都是顺序执行的,但是在并发编程的领域里,如果从顺序编程获取的直觉可能让我们加倍迷茫。
在此我们需要理解什么是并发:
百科:当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间 段分配给各个线程执行,在一个时间段的线程代码运行时,其它线程处于挂起状。.这种方式我们称之为并发(Concurrent)。
(这个是普通函数的运行模式,main将其控制权交给调用的函数,最后在返回给main)
我的理解:举个例子,我一边在上网课,一边在做笔记,我在做笔记的时候需要将网课暂停,等我的笔记做完后又继续看网课,这两件事就可以看作是一个并发的过程。
(协程则是:main和创建的goroutine是相互作用的,相互给予控制权,就像两个人,各做各的事,并且他们也相互通信)
二、go关键字
当一个程序启动时,只有一个goroutine来调用main
,称他为主goroutine,新的goroutine通过go
关键字来进行创建,看下面例子:
func main() {
for i := 0; i < 3; i++ {
//使用go关键字创建goroutine
//匿名函数
go func() {
for j := 3; j >= 0; j-- {
fmt.Println("gorouting", j)
}
}()
fmt.Println("gorouting mian:", i)
//控制程序运行时间
time.Sleep(time.Microsecond)
}
}
当然,也可以将匿名函数拿出来:
package main
import (
"fmt"
"time")
func doWorker() {
for j := 3; j >= 0; j-- {
fmt.Println("gorouting", j)
}
}
func main() {
for i := 0; i < 3; i++ {
//使用go关键字创建goroutine
go doWroker()
fmt.Println("gorouting mian:", i)
//控制程序运行时间
time.Sleep(time.Microsecond)
}
}
先来看看打印结果:
gorouting mian: 0
gorouting 3
gorouting 2
gorouting 1
gorouting 0
gorouting mian: 1
gorouting 3
gorouting 2
gorouting 1
gorouting 0
gorouting mian: 2
gorouting 3
gorouting 2
gorouting 1
gorouting 0
第二遍运行:
gorouting mian: 0
gorouting mian: 1
gorouting 3
gorouting 2
gorouting 1
gorouting 0
gorouting 3
gorouting 2
gorouting 1
gorouting 0
gorouting mian: 2
gorouting 3
gorouting 2
gorouting 1
gorouting 0
程序解释:其实可以看出,每一遍的运行结果都是不一样的,当程序加入第一个for , i=0时,运行到关键字go
时,新的goroutine就创建了,但是程序不会立即执行新的goroutine,它会进行执行main中其余的代码,在我们的这个例子中,第一遍运行,时就是这个结果,第二遍运行时也是同样的。
func main(){
var a[10] int
for i := 0; i < 10;i++{
//使用go关键字创建goroutine
//匿名函数
go func(i int){
for{
a[i]++
}
}(i)
}
time.Sleep(time.Microsecond)
fmt.Println(a)
}
打印结果:
[39904 0 0 9122 0 7123 0 0 0 0]
程序解释:在for循环中一共创建了10个goroutine,有的goroutine执行了,有的还处于等待状态,但是我们给主goroutine的时间不多,所以有一些还来不及执行就被主goroutine杀掉了,这样我们就能理解打印结果了。
三、goroutine切换点(可能)
goroutine可能切换:
- I/O、select
- channel
- 等待锁
- 函数调用(有时)
- runtime.Gosched