这是我参加青训营的第十二天。
并发编程
协程
协程(Goroutine)可以理解成轻量级的线程,但与线程相比,它的开销非常小。因此,Go 应用程序通常能并发地运行成千上万的协程。协程看上去和线程类似,但协程是在用户层面的,它的创建、切换、停止等等由用户操作,更“轻” 。
Go 创建一个协程非常简单,只要在方法或函数调用之前加关键字 go 即可。
为确保其完整性,我们可以利用sync方法。
package main
import (
"fmt"
"sync"
"time"
)
var goRoutineWait sync.WaitGroup
func main() {
goRoutineWait.Add(1) //即将开启一个goroutine
//启发调用testfunc()
go testFunc() // 创建了协程
goRoutineWait.Wait() //在此处等待协程任务的完成
fmt.Println("程序运行结束")
}
func testFunc() {
defer goRoutineWait.Done()//表示协程任务完成
for i := 1; i <= 3; i++ {
fmt.Printf("第%d次运行\n", i)
time.Sleep(time.Second)
}
}
如果想要连续并发两次,则改为goRoutineWait.Add(2)
其中开启goroutine,还可以通过匿名函数的方式。
func main() {
goRoutineWait.Add(1)
go func() {
defer goRoutineWait.Done()
for i := 1; i <= 3; i++ {
fmt.Printf("第%d次运行\n", i)
time.Sleep(time.Second)
}
}()
goRoutineWait.Wait()
fmt.Println("程序运行结束")
}
channel通道
Go语言的CSP模型通讯方式:以通信的方式共享内存数据。 协程之间传递数据需要借助通道来完成。
make(chan 元素类型,[缓冲大小])
无缓冲 make(chan int)
有缓冲 make(chan int,2)
通道分为两种:同步通道和缓冲通道。使用同步通道要求数据的发送者和接收者必须成对出现,传送时使用箭头操作符(“<-”)。传送结束后,别忘了调用 Go SDK 内置的 close 函数关闭通道,结束整个数据传送流程。
锁lock
通过锁的操作规避数据竞争,从而保护数据安全。
首先是简单的互斥锁,locker是一开头就声明的sync.Mutex变量,locker.Lock()是加锁,locjer.Unlock是解锁。但是这样的锁无法实现真正的并发,如果想要实现并发需要使用读写互斥锁。
var testInt = 0
var syncWait sync.WaitGroup
var locker sync.Mutex
func main() {
syncWait.Add(2)
go testFunc()
go testFunc()
syncWait.Wait()
fmt.Println(testInt)
}
func testFunc() {
defer syncWait.Done()
defer locker.Unlock()
locker.Lock()
for i := 0; i < 1000; i++ {
testInt += 1
}
}