package main
import("fmt""time")functestGoRoutine(routine_num int){
for i :=1; i <5; i++{
fmt.Printf("routine_num is %d ; i is %d\n", routine_num, i)
time.Sleep(10* time.Millisecond)}}funcmain(){
gotestGoRoutine(1)gotestGoRoutine(2)
time.Sleep(100* time.Millisecond)}// routine_num is 1 ; i is 1//routine_num is 2 ; i is 1//routine_num is 2 ; i is 2//routine_num is 1 ; i is 2//routine_num is 1 ; i is 3//routine_num is 2 ; i is 3//routine_num is 2 ; i is 4//routine_num is 1 ; i is 4
package main
import"fmt"// 发送信息到信道中funcsend_data(pipline chanint, data int){
pipline <- data
}// 在信道中获取信息funcget_data(pipline chanint)int{
return<-pipline
}funcmain(){
// 定义一个信道
pipline :=make(chanint)gosend_data(pipline,200)
resData :=get_data(pipline)
fmt.Println(resData)}// 200
2.2: 单向信道
package main
import("fmt""time")// Sender 定义只写信道类型type Sender =chan<-int// Receiver 定义只读信道类型type Receiver =<-chanintfuncmain(){
var pipline =make(chanint)gofunc(){
var sender Sender = pipline
fmt.Println("准备发送数据: 100")
sender <-100}()gofunc(){
var receiver Receiver = pipline
num :=<-receiver
fmt.Printf("接收到的数据是: %d", num)}()// 主函数sleep,使得上面两个goroutine有机会执行
time.Sleep(time.Second)}
2.3: 遍历信道
遍历信道,要确保信道是处于关闭状态,否则循环会阻塞。
package main
import"fmt"funcaddDataToChan(myChan chanint){
for i :=1; i <=5; i++{
myChan <- i
}// 关闭信道close(myChan)}funcmain(){
// 定义一个信道
myChan :=make(chanint,5)// 信道中加入值, 然后关闭信道addDataToChan(myChan)// 遍历信道for myChanData :=range myChan {
fmt.Printf("myChan is %d\n", myChanData)}}//myChan is 1//myChan is 2//myChan is 3//myChan is 4//myChan is 5
2.4: 信道做锁
package main
import("fmt""time")funcincrement(ch chanbool, x *int){
// 当前协程在信道存上值,其他的协程就一直阻塞中。
ch <-true*x =*x +1<-ch
}funcmain(){
// 注意要设置容量为 1 的缓冲信道
pipline :=make(chanbool,1)var x intfor i :=0; i <1000; i++{
goincrement(pipline,&x)}
time.Sleep(time.Second)
fmt.Println("x 的值:", x)}
三: select-case的用法
使用范围: 仅支持通道使用
作用: 在运行 select 时,会遍历所有(如果有机会的话)的 case 表达式,只要有一个信道有接收到数据,那么 select 就结束。
特性: select中的case是随机执行的,而不是顺序执行的。
注意: 尽量都要写default语句, 如果没写, 又没有命中case则会抛出异常。
基本使用案例:
package main
import("fmt""sync")// 定义两个信道,开两个协程, 往信道中追加数据, 测试结果。funcsendDataToChan(inputChan chanint, inputData int, wg *sync.WaitGroup){
defer wg.Done()
inputChan <- inputData
}funcmain(){
chan01 :=make(chanint,1)
chan02 :=make(chanint,1)var wg sync.WaitGroup
wg.Add(2)gosendDataToChan(chan01,1,&wg)gosendDataToChan(chan02,2,&wg)
wg.Wait()select{
case outData :=<-chan01:
fmt.Printf("outData is %d\n", outData)case outData :=<-chan02:
fmt.Printf("outData is %d\n", outData)default:
fmt.Printf("no data\n")}}//outData is 2//outData is 1
package main
import("context""fmt""time")funcmonitor(ctx context.Context, number int){
for{
select{
// 上下文关闭case v :=<-ctx.Done():
fmt.Printf("监控器%v,接收到通道值为:%v,监控结束。\n", number, v)returndefault:
fmt.Printf("监控器%v,正在监控中...\n", number)
time.Sleep(2* time.Second)}}}funcmain(){
// 实例化上下文
ctx, cancel := context.WithCancel(context.Background())// 开启多个协程for i :=1; i <=5; i++{
gomonitor(ctx, i)}
time.Sleep(1* time.Second)// 关闭所有 goroutinecancel()
time.Sleep(5* time.Second)
fmt.Println("主程序退出!!")}
六: WaitGroup
作用: 主函数, 等一堆协程结束后再执行。
作用: 用于协程之间的流程控制。
package main
import("fmt""sync")funcworker(x int, wg *sync.WaitGroup){
// 计数器 -1defer wg.Done()for i :=0; i <5; i++{
fmt.Printf("worker %d: %d\n", x, i)}}funcmain(){
var wg sync.WaitGroup
// 计数器 +2
wg.Add(2)goworker(1,&wg)goworker(2,&wg)//阻塞, 直到计数器归0
wg.Wait()}
七:互斥锁与读写锁
互斥锁:
package main
import("fmt""sync")funcadd(count *int, wg *sync.WaitGroup, lock *sync.Mutex){
lock.Lock()*count =*count +1
lock.Unlock()
wg.Done()}funcmain(){
var wg sync.WaitGroup
// 定义一个互斥锁
lock :=&sync.Mutex{
}
count :=0
wg.Add(10000)// 开1000个协程for i :=1; i <=10000; i++{
goadd(&count,&wg, lock)}
wg.Wait()
fmt.Println("count 的值为:", count)}//count 的值为: 10000