4.4 併發技術4:同步排程
阿新 • • 發佈:2018-12-09
等待組
import (
"time"
"fmt"
"sync"
)
//主協程等待子協程全部結束:通過管道阻塞
func main0() {
chanRets := make(chan int, 3)
fmt.Println(len(chanRets),cap(chanRets))
for i := 0; i < 3; i++ {
go func(index int) {
ret := getFibonacci(index)
chanRets <- ret
fmt.Println(index,ret)
}(i)
}
for {
if len(chanRets)==3{
time.Sleep(time.Nanosecond)
break
}
}
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 3; i++ {
//等待組中協程數+1(主協程中)
wg.Add(1)
go func(index int) {
ret := getFibonacci(index)
fmt.Println(index,ret)
//等待組中協程數-1(子協程中)
wg.Done()
}(i)
}
//阻塞至等待組中的協程數為0
wg.Wait()
}
func getFibonacci(n int) int {
x, y := 1, 1
for i := 0; i < n; i++ {
x, y = y, x+y
}
<-time.After(3 * time.Second)
return x
}
互斥鎖案例1
package main
import (
"fmt"
"time"
"sync"
)
func main() {
//必須保證併發安全的資料
type Account struct {
money float32
}
var wg sync.WaitGroup
account := Account{1000}
fmt.Println(account)
//資源互斥鎖(誰搶到鎖,誰先訪問資源,其他人阻塞等待)
//全域性就這麼一把鎖,誰先搶到誰操作,其他人被阻塞直到鎖釋放
var mt sync.Mutex
//銀行卡取錢
wg.Add(1)
go func() {
//拿到互斥鎖
mt.Lock()
//加鎖的訪問
fmt.Println("取錢前:",account.money)
account.money -= 500
time.Sleep(time.Nanosecond)
fmt.Println("取錢後:",account.money)
wg.Done()
//釋放互斥鎖
mt.Unlock()
}()
//存摺存錢
wg.Add(1)
go func() {
//拿到互斥鎖(如果別人先搶到,則阻塞等待)
mt.Lock()
fmt.Println("存錢前:",account.money)
account.money += 500
time.Sleep(time.Nanosecond)
fmt.Println("存錢後:",account.money)
wg.Done()
//釋放互斥鎖
mt.Unlock()
}()
wg.Wait()
}
互斥鎖案例2
package main
import (
"sync"
"fmt"
"time"
)
//必須保證併發安全的資料
type Account struct {
name string
money float32
//定義該資料的互斥鎖
mt sync.Mutex
}
//本方法不能被併發執行——併發安全的
func (a *Account) saveGet(amount float32) {
//先將資源鎖起來
a.mt.Lock()
//執行操作
fmt.Println("操作前:", a.money)
a.money += amount
fmt.Println("操作後:", a.money)
<-time.After(3 * time.Second)
//釋放資源
a.mt.Unlock()
}
//本方法可以被併發執行——不是併發安全的,無此必要
func (a *Account) getName() string {
return a.name
}
func main() {
a := Account{name: "張全蛋", money: 1000}
var wg sync.WaitGroup
wg.Add(1)
go func() {
//呼叫一個加鎖的方法(同步)
a.saveGet(500)
wg.Done()
}()
wg.Add(1)
go func() {
//呼叫一個加鎖的方法(同步)
a.saveGet(-500)
wg.Done()
}()
for i:=0;i<3 ;i++ {
wg.Add(1)
go func() {
//呼叫一個普通的沒有訪問鎖的方法(非同步)
fmt.Println(a.getName())
wg.Done()
}()
}
wg.Wait()
}
通過訊號量控制併發數
package main
import (
"fmt"
"time"
"sync"
)
/*訊號量:通過控制管道的“頻寬”(快取能力)控制併發數*/
func main() {
//定義訊號量為5“頻寬”的管道
sema = make(chan int, 5)
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func(index int) {
ret := getPingfangshu(index)
fmt.Println(index, ret)
wg.Done()
}(i)
}
wg.Wait()
}
//該函式只允許5併發執行
var sema chan int
func getPingfangshu(i int) int {
sema <- 1
<-time.After(2 * time.Second)
<- sema
return i
}