介紹
線程:輕量級進程
攜程:輕量級線程
并發(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")
}

