1.1 Goroutine
goroutine是Go语言中的一种轻量级线程,用于实现迸发操作,其优点是创建与销毁的资源消耗较小,可以高效复用系统资源。 Go语言通过goroutine能够自动实现进程、线程、协程,只需在函数或者方法前加上go关键字。
线程和协程
线程:线程从属于进程,是线程的实际执行者,一个进程至少包含一个主线程,也可以有更多子线程。线程共享进程的地址空间和资源,一个进程下的线程可以共享访问的数据和变量,同时线程内可以包含多的协程。 协程:是一种比线程更加轻量化的存在,协程不被操作系统内核管理,完全由程序所控制,切换代价非常低。协程能够在一个线程中并发执行,通过切换协程交替执行任务。
使用goroutine快速打印
package main
import (
"fmt"
"time"
)
func hello(i int){
fmt.Println("hello goroutine:"+fmt.Sprint(i))
}
func HelloGoRoutine(){
for i := 0;i<5;i++{
go func(j int){
hello(j)
}(i)
}
time.Sleep(time.Second)//保证子协程执行完之前主线程不退出
}
func main(){
HelloGoRoutine()
}
运行结果
hello goroutine:4
hello goroutine:2
hello goroutine:3
hello goroutine:0
hello goroutine:1
可以看出结果是乱序的,表明程序的执行是并行的,不是按顺序的。
1.2 CSP(Communication Sequential Processes)
提倡通过通信来共享内存而不是通过共享内存来实现通信。 不同的协程之间通过channel来连接。 channel遵循先入先出,保证收发数据的顺序。
1.3 Channel
make(chan 元素类型,[缓冲大小])
无缓冲通道:make(chan int) 有缓冲通道: make(chan int,2)//缓冲容量为2
package main
import (
"fmt"
)
func CalSquare(){
src := make(chan int)
dest := make(chan int,3)
go func(){
defer close(src)
for i:= 0;i<10;i++{
src <- i
}
}()
go func(){
defer close(dest)
for i:=range src{
dest <- i*i
}
}()
for i:= range dest{
fmt.Println(i)
}
}
func main(){
CalSquare()
}
在这个程序中使用src这个channel实现了产生数和计算平方两个子协程间的通信,使用dest实现计算平方和主协程间的通信。由于实际的主协程逻辑可能更加复杂,子协程传递的数据可能不会被立即读取和使用,所以dest为有缓冲的channel。
程序运行结果:
0
1
4
9
16
25
36
49
64
81
输出结果为有序数列,所以channel能够保证并发的安全性。
1.4 WaitGroup
Add(delta int)//启动了n个并发任务,计数器+n Done()//执行结束一个并发任务,计数器-1 Wait()//主协程阻塞直到计数器为0
package main
import (
"fmt"
"sync"
)
func ManyGowait(){
var wg sync.WaitGroup
wg.Add(5)
for i:= 0;i<5;i++{
go func(j int){
defer wg.Done()
fmt.Println("hello goroutine:"+fmt.Sprint(j))
}(i)
}
wg.Wait()
}
func main(){
ManyGowait()
}
程序运行结果:
hello goroutine:4
hello goroutine:1
hello goroutine:0
hello goroutine:3
hello goroutine:2