Go语言进阶部分笔记|青训营

73 阅读2分钟

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