引用一下golang互斥鎖和讀寫鎖效能分析中關於互斥鎖和讀寫鎖的定義,比較清楚
1.互斥鎖有兩種操作,獲取鎖和釋放鎖
2.當有乙個goroutine獲取了互斥鎖後,任何goroutine都不可以獲取互斥鎖,只能等待這個goroutine將互斥鎖釋放
3.互斥鎖適用於讀寫運算元量差不多的情況
4.讀寫都可以放入互斥鎖中
1.讀寫鎖有四種操作 讀上鎖 讀解鎖 寫上鎖 寫解鎖
2.寫鎖最多有乙個,讀鎖可以有多個(最大個資料說和cpu個數有關)
3.寫鎖的優先順序高於讀鎖,這是因為為了防止讀鎖過多,寫鎖一直堵塞的情況發生
4.當有乙個goroutine獲得寫鎖時,其他goroutine不可以獲得讀鎖或者寫鎖,直到這個寫鎖釋放
5.當有乙個goroutine獲得讀鎖時,其他goroutine可以獲得讀鎖,但是不能獲得寫鎖。所以由此也可得知,如果當乙個goroutine希望獲取寫鎖時,不斷地有其他goroutine在獲得讀鎖和釋放讀鎖會導致這個寫鎖一直處於堵塞狀態,所以讓寫鎖的優先順序高於讀鎖可以避免這種情況,
6.讀寫鎖適用於讀多寫少的情景。
7.在讀取操作多的情況下,比如現在有三個goroutine:g1,g2,g3都想要讀取一段資料a,我們如果用互斥鎖的話,就是以下的情形:g1先加鎖,然後讀取a,然後釋放;然後g2加鎖,讀取a,釋放;g3加鎖,讀取a,然後釋放…這個操作是序列的,由於每個goroutine都需要排隊等待前乙個goroutine釋放鎖,所以效率顯然不高;但是如果這個時候我們用讀寫鎖就可以讓g1,g2,g3同時讀a,就可以大大的提公升效率。
8.寫操作只能放在寫鎖中,讀操作可以放在讀寫鎖中,但是放在寫鎖中肯定併發效率低
在本機上跑博主提供的原**時,結果與博主相反
package main
import
("fmt"
"sync"
"time"
)const maxnum =
1000
//map的大小
const locknum =
1e7//加鎖次數
var lock sync.mutex //互斥鎖
var rwlock sync.rwmutex //讀寫鎖
var lock_map map
[int
]int
//互斥鎖map
var rwlock_map map
[int
]int
//讀寫鎖map
func
main()
var rwlock_w =
&sync.waitgroup
lock_w.
add(locknum)
rwlock_w.
add(locknum)
lock_ch :=
make
(chan
int,
10000
) rwlock_ch :=
make
(chan
int,
10000
) lock_map =
make
(map
[int
]int
, maxnum)
rwlock_map =
make
(map
[int
]int
, maxnum)
init_map
(lock_map, rwlock_map)
time1 := time.
now(
)for i :=
0; i < locknum; i++
lock_w.
wait()
time2 := time.
now(
)for i :=
0; i < locknum; i++
rwlock_w.
wait()
time3 := time.
now(
) fmt.
println
("lock time:"
, time2.
sub(time1)
.string()
) fmt.
println
("rwlock time:"
, time3.
sub(time2)
.string()
)}func
init_map
(a map
[int
]int
, b map
[int
]int)}
func
test1
(ch chan
int, i int
, mymap map
[int
]int
, w *sync.waitgroup)
intfunc
test2
(ch chan
int, i int
, mymap map
[int
]int
, w *sync.waitgroup)
int
out:
lock time: 3.6869219s
rwlock time: 2.7925313s
但是可以看到二者的數量級在併發數達到1e7時仍然比較接近
下面我們增加chan傳遞(通用情景),同時增加任務中的耗時(這會增加互斥鎖的序列負擔)
package main
import
("fmt"
"sync"
"time"
)const maxnum =
1000
//map的大小
const locknum =
1e5//加鎖次數
var lock sync.mutex //互斥鎖
var rwlock sync.rwmutex //讀寫鎖
var lock_map map
[int
]int
//互斥鎖map
var rwlock_map map
[int
]int
//讀寫鎖map
func
main()
gofunc()
()for i :=
range lock_ch
fmt.
printf
("chan id sum %d\n"
, count1)
time2 := time.
now(
)for i :=
0; i < locknum; i++
gofunc()
()for i :=
range rwlock_ch
fmt.
printf
("chan id sum %d\n"
, count2)
time3 := time.
now(
) fmt.
println
("lock time:"
, time2.
sub(time1)
.string()
) fmt.
println
("rwlock time:"
, time3.
sub(time2)
.string()
)}func
init_map
(a map
[int
]int
, b map
[int
]int)}
func
test1
(ch chan
int, i int
, mymap map
[int
]int
, w *sync.waitgroup)
intfunc
test2
(ch chan
int, i int
, mymap map
[int
]int
, w *sync.waitgroup)
int
out:
chan id sum 4999950000
chan id sum 4999950000
lock time: 2m50.2909581s
rwlock time: 124.6928ms
可以看到兩種鎖明顯不在乙個數量級上
將互斥鎖換為讀寫鎖的寫鎖,結果與之前測試相同
讀寫鎖在多讀的時候,由於其避免了互斥鎖的序列性,效能上遠優於互斥鎖
互斥鎖和讀寫鎖
互斥鎖的型別 對資源的訪問是互斥的,即執行緒a對資源加鎖後,在a解鎖前,其他執行緒不能訪問這個加鎖的資源。互斥鎖的特點 多個執行緒訪問資源的時候是序列的 互斥鎖的使用步驟 建立乙個互斥鎖 pthread mutex t mutex 初始化這把鎖 pthread mutex init mutex,nu...
Go 互斥鎖和讀寫互斥鎖的實現
目錄 先來看這樣一段 所存在的問題 var wg sync.waitgroup var x int64 func main func f wg.done 這裡為什麼輸出是 12135 不同的機器結果不一樣 而不是20000。因為 x 的賦值,總共分為三個步驟 取出x的值 計算x的結果 給x賦值。那麼...
linux之mutex 互斥鎖
在posix thread中定義有一套專門用於執行緒同步的mutex函式 有兩種方法建立互斥鎖,靜態方式和動態方式。posix定義了乙個巨集pthread mutex initializer來靜態初始化互斥鎖,方法如下 pthread mutex t mutex pthread mutex init...