iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 15
1

多執行序問題的解決

在上一篇介紹了多執行序的好處以及撰寫方式,但是也提到了多執行序的問題,所以這篇針對多執行序遇到的race condition在 go 語言如何解決它來說明。

本文同步放置於此

多執行序的鎖

在程式執行的過程中可能會做一個改變物件屬性的動作,然而在多執行序下會因為這個動作產生一個問題,就是後面執行的會把前面執行的結果給蓋掉。
所以通常的解決方式就是加一個鎖 mutex 讓要更改這物件的執行序排隊來更改,接下來就跟大家介紹如何撰寫這個鎖。

鎖如何撰寫

這時還是一樣請大家先看看Go Tour的範例

package main

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

// SafeCounter is safe to use concurrently.
type SafeCounter struct {
	v   map[string]int
	mux sync.Mutex
}

// Inc increments the counter for the given key.
func (c *SafeCounter) Inc(key string) {
	c.mux.Lock()
	// Lock so only one goroutine at a time can access the map c.v.
	c.v[key]++
	c.mux.Unlock()
}

// Value returns the current value of the counter for the given key.
func (c *SafeCounter) Value(key string) int {
	c.mux.Lock()
	// Lock so only one goroutine at a time can access the map c.v.
	defer c.mux.Unlock()
	return c.v[key]
}

func main() {
	c := SafeCounter{v: make(map[string]int)}
	for i := 0; i < 1000; i++ {
		go c.Inc("somekey")
	}

	time.Sleep(time.Second)
	fmt.Println(c.Value("somekey"))
}

相信有閱讀筆者前幾篇文章可以理解上面的程式在做甚麼,這邊針對 make 關鍵字加以說明。
這個 make 主要的用途就是產生一個記憶體空間給變數,所以簡單講上面的例子就是產生一個key是字串value是整數的map給變數 c 的屬性 v 。
接下來在下一個段落說明一下 mutex 的運作方式。

鎖的運作方式

搭配上面的例子,主要是在 Inc 跟 Value 這兩個方法,因為要避免race condition的問題所以不管在存取前都要加上一個鎖,限制只能有一個執行序來存取變數,而其他未取得鎖的直行序會等待鎖解開之後取得鎖在執行。
所以在新增之前要先呼叫 c.Mutex.Lock() 來取得鎖,並鎖住執行序來更新該變數,等到更新完了之後一定要記得呼叫 c.mux.Unlock() 來解鎖,不然就永遠沒有可以執行存取變數的權限了,而其他執行序也不能繼續執行下去。
因此在 Value 這方法也是需要取的鎖來取的變數的值,正因為需要回傳值,所以這邊用到了 defer 待回傳值之後會呼叫 c.mux.Unlock() 來解鎖。
其實也可以在前面先寫下 defer c.mux.Unlock() 來避免方法結束後沒有解鎖的窘境。

結論

這篇跟大家介紹多執行序如何利用 mutex 來解決race condition的問題,也針對相關語法做進一步說明,希望對大家的 go 多執行序編程能有些幫助。


上一篇
執行序的基礎
下一篇
套件
系列文
Iris這個在go語言上地表最快的網頁框架30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言