1. 程式人生 > >4.4 併發技術4:同步排程

4.4 併發技術4:同步排程

等待組

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
}