gorutine的定义:
1.任何函数只需要加上go就能送给调度器运行
2.调度器在合适的点进行切换(可能切换的点:I/O,select,channel,等待锁,函数调用(有时),runtime.Gosched()
3.只是参考,不能保证切换,不能保证在其他地方不切换
下面通过代码来详细讲解一下goroutine的用法:
package main
import (
"fmt"
"time"
)
func main() {
for i := 0; i < 10; i++ {
go func(i int) {
for {
fmt.Printf("Hello from"+
"goroutine %d\n", i)
}
}(i)
}
time.Sleep(time.Millisecond) //如果没有加此行代码,由于main函数与go func是并发执行的,go func还没来得急打印main函数就已经退出了,所以goroutine就被杀死了,所以没有输出结果。
//fmt.Println(a)
}
上述代码如果没有加go,就表示不是并发执行,而且因为该函数没有退出条件,会一直打印Hello form gorutine 0,加了go之后就表示创建了10个协程并发进行运行。
输出结果:
如果上述代码中10改为1000,那么就不是所有结果都会在Millsecond之内输出了。
goroutine其实 是一种协程coroutine.或者说是与协程比较相像的。
协程Coroutine
1.轻量级“线程”(例如我们在前面可以开1000个线程)
2.非抢占式多任务处理,有协程主动交出控制权,线程我们都知道它任何时候都有可能被操作系统所切换,是抢占的,但协程不一样,是非抢占式的。
3.编译器、解释器、虚拟机层面的多任务
4.多个协程可能在一个或者多个线程上运行(由调度器决定)
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
var a [10]int
for i := 0; i < 10; i++ {
go func(i int) {
for {
a[i]++
runtime.Gosched()
}
}(i)
}
time.Sleep(time.Millisecond) //如果没有加此行代码,由于main函数与go func是并发执行的,go func还没来得急打印main函数就已经退出了,所以goroutine就被杀死了,所以没有输出结果。
fmt.Println(a)
}
上述代码runtime.Gosched()手动交出控制权,会让别人也能运行,因为上述代码go func是一个协程,因为该代码为死循环,所以没有办法交出控制权,会死循环挂掉。而之前因为printf涉及i,o操作,会有协程之间的切换,所以能输出的结果,但是因为a【i】++没有涉及协程之间的切换,所以会挂掉,所以可以加上runtime.Gosched()手动交出控制权。
输出结果:
小结:
main函数可以开出很多协程,让这些协程并发执行,而且这些协程也有可能映射到一个线程上运行。