并發(fā)編程

介紹

線程:輕量級進程
攜程:輕量級線程

并發(fā)

協(xié)程

mac活動監(jiān)視器=任務管理器

線程:進程中的執(zhí)行路徑

package main

import "fmt"

//9
func main() {
    /*
    一個goroutine打印數(shù)字,另外一個goroutine打印字母,觀察運行結果
    */
    //1. 先創(chuàng)建并啟動子goroutine,執(zhí)行printNum()
    go printNum()

    //2. main打印字母
    for i:=1;i<=100;i++ {
        fmt.Printf("\t主goroutine打印字母:A %d\n",i)
    }

    fmt.Println("main over...")

}

func printNum(){
    for i:=1;i<=100;i++ {
        fmt.Printf("子goroutine打印數(shù)字:%d\n",i)
    }
}

主goroutine結束,程序就結束了,不管子goroutine,可以用管道通信

與函數(shù)不同,所以寫了返回值也沒有用

啟動多個goroutine

并發(fā)模型

runtime包

類似與虛擬機,管理內存

package main

import (
    "fmt"
    "runtime"
    "time"
)

//10
func main() {
    //獲取goroot目錄
    fmt.Println("GOROOT---->",runtime.GOROOT()) //GOROOT----> /usr/local/go

    //獲取操作系統(tǒng)
    fmt.Println("os/platform---->",runtime.GOOS) //os/platform----> darwin,mac系統(tǒng)

    //獲取邏輯cpu的數(shù)量
    fmt.Println("邏輯CPU的數(shù)量---->",runtime.NumCPU()) //邏輯CPU的數(shù)量----> 8

    //設置cpu數(shù)量,不要亂寫,寫當前邏輯cpu數(shù)量就行,最好寫在init函數(shù)
    //n := runtime.GOMAXPROCS(16)
    //fmt.Println(n)

    //gosched讓出當前時間片,讓別的goroutine先執(zhí)行
    go func(){
        for i := 0; i < 5; i++ {
            fmt.Println("goroutine...")
        }
    }()

    for i := 0; i < 5; i++ {
        //讓出時間片,先讓別的goroutine執(zhí)行
        runtime.Gosched()
        fmt.Println("main...")
    }

    //創(chuàng)建goroutine
    go func() {
        fmt.Println("goroutine開始")
        //調用fun
        fun()
        fmt.Println("goroutine結束")
    }()

    //睡一會
    time.Sleep(3 * time.Second)


}

func fun(){
    defer fmt.Println("defer...")
    // return //終止函數(shù)
    runtime.Goexit() //終止當前的goroutine
    fmt.Println("fun函數(shù)")
}

臨界資源的安全問題

package main

import (
    "fmt"
    "time"
)

//11
func main() {
    /*
    臨界資源
    */
    a := 1
    go func() {
        a = 2
        fmt.Println("goroutine中a:",a)
    }()

    a = 3
    time.Sleep(1)
    fmt.Println("main goroutine...",a)

}
package main

import (
    "fmt"
    "math/rand"
    "time"
)

//11
func main() {
    /*
    臨界資源
    */
    a := 1
    go func() {
        a = 2
        fmt.Println("goroutine中a:",a)
    }()

    a = 3
    time.Sleep(1)
    fmt.Println("main goroutine...",a)

    /*
    4個goroutine,模擬4個售票口
    */
    go saleTickets("售票口1")
    go saleTickets("售票口2")
    go saleTickets("售票口3")
    go saleTickets("售票口4")

    time.Sleep(5 * time.Second)

}

//全局變量
var ticket = 10

func saleTickets(name string) {
    for{
        if ticket > 0 {
            rand.Seed(time.Now().UnixNano())
            time.Sleep(time.Duration(rand.Intn(1000))*time.Millisecond)
            fmt.Println(name,"售出",ticket)
            ticket--
        }else {
            fmt.Println(name,"售罄,沒有票了。。")
            break
        }
    }
}

不鼓勵通過共享內存通信,鼓勵通過通信來共享內存

channel

sync包下的WaitGroup同步等待組

package main

import (
    "fmt"
    "sync"
)

var wg sync.WaitGroup //創(chuàng)建同步等待組的對象

//11
func main() {
    /*
        waitgroup:同步等待組
            Add(),設置等待組中要執(zhí)行的子 goroutine 的數(shù)量

            Wait(),讓主goroutine等待
    */

    wg.Add(2)

    go fun1()
    go fun2()

    //無輸出

    fmt.Println("main進入阻塞,等待wg的子groutine結束")
    wg.Wait()
    fmt.Println("main阻塞解除")

}

func fun1(){
    for i := 1; i < 10; i++ {
        fmt.Println("fun1打印 a", i)
    }

    wg.Done() //給wg等待組count數(shù)值減1 == add(-1)
}

func fun2(){
    defer wg.Done()
    for i := 1; i < 10; i++ {
        fmt.Println("\tfun2打印 b", i)
    }
}

如果沒有wg.Done()

如果是1,隨便抓一個

互斥鎖

互斥鎖、讀寫鎖

package main

import (
    "fmt"
    "math/rand"
    "sync"
    "time"
)

var wg sync.WaitGroup

//13
func main() {

    /*
        4個goroutine,模擬4個售票口
    */
    wg.Add(4)
    go saleTickets2("售票口1")
    go saleTickets2("售票口2")
    go saleTickets2("售票口3")
    go saleTickets2("售票口4")

    wg.Wait()
    fmt.Println("main over")

}

//全局變量
var ticket = 10

var mutex sync.Mutex //創(chuàng)建鎖

func saleTickets2(name string) {
    rand.Seed(time.Now().UnixNano())
    defer wg.Done()
    for{
        //上鎖
        mutex.Lock()
        if ticket > 0 {
            time.Sleep(time.Duration(rand.Intn(1000))*time.Millisecond)
            fmt.Println(name,"售出",ticket)
            ticket--
        }else {
            mutex.Unlock() //條件不滿足也要解鎖
            fmt.Println(name,"售罄,沒有票了。。")
            break
        }
        //解鎖
        mutex.Unlock()
    }
}

建議使用defer語句解鎖

讀寫鎖

package main

import (
    "fmt"
    "sync"
    "time"
)

var wg sync.WaitGroup

var rwMutex *sync.RWMutex

//14
func main() {
    /*
    讀寫鎖
    */
    rwMutex = new(sync.RWMutex)

    //wg.Add(2)
    //
    ////讀操作可以同時進行
    //go readData(1)
    //go readData(2)

    wg.Add(3)
    go writeData(1)
    go readData(2)
    go writeData(3)

    wg.Wait()
    fmt.Println("main over")

}

func writeData(i int){
    defer wg.Done()

    fmt.Println(i,"開始寫:write start。。")

    rwMutex.Lock() //讀操作上鎖
    fmt.Println(i,"正在寫")
    time.Sleep(1 * time.Second)
    rwMutex.Unlock() //讀操作解鎖
    fmt.Println(i,"寫結束:write over")
}

func readData(i int){
    defer wg.Done()

    fmt.Println(i,"開始讀:read start。。")

    rwMutex.RLock() //讀操作上鎖
    fmt.Println(i,"正在讀取")
    time.Sleep(1 * time.Second)
    rwMutex.RUnlock() //讀操作解鎖
    fmt.Println(i,"讀結束:read over")

}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容