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) }}
直播中

尚未有邦友留言

立即登入留言