10.Go-goroutine,waitgroup,互斥鎖,channel和select

10.1.goroutine

goroutine的使用緩存

//Learn_Go/main.go
package main

import (
	"fmt"
	"time"
)

func demo(count int)  {
	for i :=1; i < 10; i++{
		fmt.Println(count,":",i)
	}
}

func main() {
	for i :=1; i < 10; i++{
		go demo(i)
	}
	//添加休眠時間等待goroutine執行結束
	time.Sleep(3e9)
}

10.2.waitgroup

WaitGroup直譯爲等待組,其實就是計數器,只要計數器中有內容將一直阻塞安全

WaitGroup有三種方法併發

  • Add(delta int)表示向內部計數器添加增量(delta),其中參數delta能夠使負數
  • Done() 表示減小waitgroup計數器的值,應當在程序最後執行,至關於Add(-1)
  • Wait()  表示阻塞知道waitgroup計數器爲0
//Learn_Go/main.go
package main

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup
	wg.Add(5)
	for i := 0; i < 5; i++{
		go func(j int) {
			fmt.Println("第",j,"次執行")
			wg.Done()
		}(i)
	}
	wg.Wait()
	fmt.Println("程序結束")
}

10.3.互斥鎖和讀寫鎖

(1)互斥鎖函數

能夠使用sync.Mutex對內容加鎖,互斥鎖的使用場景spa

  • 多個gouroutine訪問同一個函數代碼段
  • 操做一個全局變量
  • 爲了保證共享變量安全性,值安全性

 (2)讀寫鎖線程

Go語言中的map不是線程安全的,多個gouroutine同時操做會出現錯誤blog

RWMutex能夠添加多個讀鎖或者一個寫鎖,讀寫鎖不能同時存在進程

map在併發下讀寫就須要結合讀寫鎖完成同步

互斥鎖表示鎖的代碼同一時間只能有一個goroutine運行,而讀寫鎖表示在鎖範圍內數據的讀寫操做string

//Learn_Go/main.go
package main

import (
	"fmt"
	"sync"
)

func main() {
	var rwm sync.RWMutex
	var wg sync.WaitGroup
	wg.Add(10)
	m := make(map[int]int)
	for i := 0; i < 10; i++{
		go func(j int) {
			rwm.Lock()
			m[j] = j
			fmt.Println(m)
			rwm.Unlock()
			wg.Done()
		}(i)
	}
	wg.Wait()
	fmt.Println("程序結束")
}

10.4.channel

channel是進程內通訊方式,每一個channel只能傳遞一個類型的值,這個類型須要在聲明channel時指定

channel在Go中主要的兩個做用:同步和通訊

(1)聲明channel的語法

  • var 名稱 chan 類型
  • var 名稱 chan <- 類型       只寫
  • var 名稱 <- chan 類型       只讀
  • 名稱 := make(chan int)      無緩存chanel
  • 名稱 := make(chan int)      無緩存channel
  • 名稱 := make(chan int,100)     有緩存channel

 (2)操做channel的語法

  • ch <- 值          向ch中添加一個值
  • <- ch               從ch中取出一個值
  • a := <-ch         從ch中取出一個值並賦值給a
  • a,b := <-ch       從ch中取出一個值賦值給a,若是ch已經關閉或ch中沒有值,b爲false,

 (3)不管是向channel存數據仍是取數據都會阻塞

//Learn_Go/main.go
package main

import "fmt"

func main() {
	ch := make(chan int)
	go func() {
		fmt.Println("執行")
		ch <- 111     
	}()
	a := <- ch
	fmt.Println(a)
	fmt.Println("程序結束")
}

 (4)使用channel實現gouroutine之間通訊

//Learn_Go/main.go
package main

import "fmt"

func main() {
	ch1 := make(chan string)
	ch2 := make(chan int)

	go func() {
		ch1 <- "derek"
		ch2 <- 111
	}()

	go func() {
		content := <- ch1
		fmt.Println("取出數據:",content)       //取出數據: derek
		ch2 <- 222
	}()

	a := <- ch2
	b := <- ch2
	fmt.Println(a,b)              //111 222
	fmt.Println("程序結束")
}

 (5)能夠使用for range獲取channel中內容

//Learn_Go/main.go
package main

import "fmt"

func main() {
	ch1 := make(chan int)
	ch2 := make(chan int)

	go func() {
		for i := 0; i<10;i++{
			ch1 <- i
		}
		ch2 <- 222
	}()

	go func() {
		for n := range ch1{
			fmt.Println(n)
		}
	}()
	<- ch2
	fmt.Println("程序結束")
}

10.5.select

select執行過程

  • 每一個case必須是一個IO操做
  • 哪一個case能夠執行就執行哪一個
  • 全部case都不能執行時,執行default
  • 全部case都不能執行且沒有default,將會阻塞
//Learn_Go/main.go
package main

import "fmt"

func main() {
	ch1 := make(chan int,2)       //有緩存的channel
	ch2 := make(chan int,3)
	ch1 <- 111
	ch2 <- 222
	select {
	case a := <-ch1:
		fmt.Println(a)
	case b := <-ch2:
		fmt.Println(b)
	default:
		fmt.Println("錯誤")
	}
}

 select多和for循環結合使用

//Learn_Go/main.go
package main

import "fmt"

func main() {
	ch := make(chan int)
	for i := 0; i < 10;i++{
		go func(j int) {
			ch <- j
		}(i)
	}
	//用for循環一直接受
	for {
		select {
		case a := <- ch:
			fmt.Println(a)
		default:
		}
	}
}
相關文章
相關標籤/搜索