go並發編程 WaitGroup, Mutex


1.背景

記錄一下,方便后續寫代碼直接使用。
需要注意幾點:

  • chan 默認支持多協程工作,不需要加鎖。
  • 其他變量操作需要使用鎖保護(map多協程並發寫會panic, 並且無法捕獲)。
  • 啟動goroutine時, 通常需要傳遞參數。不讀取局部變量。
  • 需要使用waitgroup等待所有goroutine的退出(即使部分goroutine出現panic也需要wg.Done())
  • 每個goroutine都必須捕獲panic, 否則panic會導致進程會掛掉。

2. 統一panic判斷函數:COMMON_PANIC_CAPTURE

在工作中遇到過,由於panic 日志打印不統一在panic監控出現漏報情況。
通過封裝panic判斷函數,統一日志打印,方便監控添加,避免漏報情況。

package main

import (
	"fmt"
	"runtime/debug"
	"sync"
	"time"
)

func COMMON_PANIC_CAPTURE(panicErr interface{}) (bool){	//封裝一個panic判斷/日志打印函數
	if panicErr != nil {
		fmt.Printf("PANIC err:%v, stack:%s\n", panicErr, debug.Stack())
		return true
	}
	return false
}

func main() {
	var wg sync.WaitGroup
	for i := 0; i < 3; i=i+1 {
		go func(x int){	 //啟動go時, 需要注意參數傳遞
			wg.Add(1)
			defer func() {
				wg.Done()
				COMMON_PANIC_CAPTURE(recover())
			}()
			if x == 2 {
				panic(fmt.Sprintf("val:%d", x))
			}
		}(i)
	}
	wg.Wait()	//等待go結束
	time.Sleep(2 * time.Second)	//等待go panic日志打印
	fmt.Printf("end ok!\n")
}

3. 並發編程例子

並發寫map panic, 程序無法捕獲,可能是go設計的一個問題。

package main

import (
	"fmt"
	"sync"
	"encoding/json"
)

func main() {
	res := make(map[string]string)
	var wg sync.WaitGroup	//group, 內部使用atomic實現計數
	var mylock sync.Mutex

	for i := 0; i < 4000; i++ {
		wg.Add(1)
		go func(par int){
			defer func() {
				wg.Done()
			}()

			//time.Sleep(3 * time.Second)
			tmp := fmt.Sprintf("%d", par %7)

			mylock.Lock()  //加鎖
			defer mylock.Unlock()  //defer確保解鎖
			res[tmp] = tmp
		}(i)
	}
	wg.Wait()

	resByte, _ := json.Marshal(res)
	fmt.Printf("%s\n", string(resByte))
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM