互斥鎖和讀寫瑣的區別

互斥鎖和讀寫鎖的區別

當多個協程進行讀寫操作時,採用互斥鎖的話,將會一個一個讀並一個一個寫,
當多個協程進行讀寫操作時,採用讀寫鎖的話,讀操作將併發進行,而寫操作將一個一個進行,相比於互斥鎖,讀寫瑣這樣能有效的節約讀的時間

示例問題

x是一個0-99的100位數的數組,y是由全是0組成的100位數組
開啓兩個讀取x的協程如下:

  • 協程1:將x中的每個元素乘以2,並讀到y中,協程2:將x中的每個元素乘以3,並讀到y中

再開啓兩個重寫x協程如下:

  • 協程3:一個將x中的每個元素乘以2,並寫入x中,協程4:將x中的每個元素乘以3,並寫到x中

此時,協程1和協程2並未對數組x進行任何寫操作,僅作了讀操作,而協程3和協程4都對x進行了寫操作

互斥鎖示例代碼如下:

func test1() {
	var x [100]int
	var y [100]int
	for i := 0; i < 100; i++ {
		x[i] = i + 1
		y[i] = 0
	}

    fmt.Println("before,  x= ", x) //此時 x爲[1-100]
	fmt.Println("before,  y= ", y) //此時 y爲[0-0]

	var wg sync.WaitGroup //用來等待,防止開啓的go協程在主函數中直接飛掉
	var lock sync.Mutex	  //互斥鎖	
	wg.Add(4) //等待的任務個數

	reader := func() {
		//協程1 將x中的每個元素x2,並讀到y中
		go func(a *[100]int, b *[100]int) {
			lock.Lock()
			defer lock.Unlock()
			for index := 0; index < len(a); index++ {
				b[index] = a[index] * 2
				fmt.Println("協程1正在讀取中..... index=", index, "value=", b[index])
			}
			fmt.Println("協程1結束,  r1 b= ", b)
			wg.Done() //結束1一個等待任務
		}(&x, &y)

		//協程2 將x中的每個元素x3,並讀到y中
		go func(a *[100]int, b *[100]int) {
			lock.Lock()
			defer lock.Unlock()
			for index := 0; index < len(a); index++ {
				b[index] = a[index] * 3
				fmt.Println("協程2正在讀取中..... index=", index, "value= ", b[index])
			}
			fmt.Println("協程2結束,  r2 b= ", b)
			wg.Done()
		}(&x, &y)
	}
    
	write := func() {
		//協程3 一個將x中的每個元素x2,並寫入x中
		go func(a *[100]int) {
			lock.Lock()
			defer lock.Unlock()
			for index := 0; index < len(a); index++ {
				a[index] *= 2
				fmt.Println("協程3正在寫..... index=", index, "value= ", a[index])
			}
			fmt.Println("協程3結束,  value= ", a)

			wg.Done()
		}(&x)

		//協程4 將x中的每個元素x3,並寫到x中
		go func(a *[100]int) {
			lock.Lock()
			defer lock.Unlock()
			for index := 0; index < len(a); index++ {
				a[index] *= 3
				fmt.Println("協程4正在寫..... index=", index, "value= ", a[index])
			}
			fmt.Println("協程4結束,  value= ", a)
			wg.Done()
		}(&x)
	}
	
	reader()			//先開始兩個讀的協程
	time.Sleep(1*time.Second)	//等待一秒
	write()				//再開啓兩個寫的協程

	wg.Wait()

	fmt.Println("result x:", x) //x的結果固定爲6-600,但過程由協程3和協程4競爭先後決定
	fmt.Println("result y:", y) //y的結果由協程1和2競爭決定,協程1在後,則爲2-200,協程2在後則爲3-300
}

在上面的示例中,我們可以看到,打印出來的結果,當讀操作時,x依次被傳入協程1和協程2中,進行相應的讀取,在其中一個讀操作結束後,再進行下一個讀操作;

讀寫鎖示例代碼如下:


func test2() {
	var x [100]int
	var y [100]int
	for i := 0; i < 100; i++ {
		x[i] = i + 1
		y[i] = 0
	}

	fmt.Println("before test1,  x= ", x)
	fmt.Println("before test1,  y= ", y)

	var wg sync.WaitGroup //用來等待,防止開啓的go協程在主函數中直接飛掉
	var lock sync.RWMutex //讀寫瑣
	wg.Add(4) //等待的任務個數

	reader := func() {
		//協程1 將x中的每個元素x2,並讀到y中
		go func(a *[100]int, b *[100]int) {
			lock.RLock()		//讀瑣開啓
			defer lock.RLock()   //讀瑣關閉
			for index := 0; index < len(a); index++ {
				b[index] = a[index] * 2
				fmt.Println("協程1正在讀取中..... index=", index, "value=", b[index])
			}
			fmt.Println("協程1結束,  r1 b= ", b)
			wg.Done() //結束1一個等待任務
		}(&x, &y)

		//協程2 將x中的每個元素x3,並讀到y中
		go func(a *[100]int, b *[100]int) {
			lock.RLock()
			defer lock.RLock()
			for index := 0; index < len(a); index++ {
				b[index] = a[index] * 3
				fmt.Println("協程2正在讀取中..... index=", index, "value= ", b[index])
			}
			fmt.Println("協程2結束,  r2 b= ", b)
			wg.Done()
		}(&x, &y)
	}
	write := func() {
		//協程3 一個將x中的每個元素x2,並寫入x中
		go func(a *[100]int) {
			lock.Lock()
			defer lock.Unlock()
			for index := 0; index < len(a); index++ {
				a[index] *= 2
				fmt.Println("協程3正在寫..... index=", index, "value= ", a[index])
			}
			fmt.Println("協程3結束,  value= ", a)

			wg.Done()
		}(&x)

		//協程4 將x中的每個元素x3,並寫到x中
		go func(a *[100]int) {
			lock.Lock()
			defer lock.Unlock()
			for index := 0; index < len(a); index++ {
				a[index] *= 3
				fmt.Println("協程4正在寫..... index=", index, "value= ", a[index])
			}
			fmt.Println("協程4結束,  value= ", a)
			wg.Done()
		}(&x)
	}

	reader()			//先開始兩個讀的協程
	time.Sleep(1*time.Second)	//等待一秒
	write()				//再開啓兩個寫的協程

	wg.Wait()

	fmt.Println("result x:", x) //x的結果固定爲6-600,但過程由協程3和協程4競爭先後決定
	fmt.Println("result y:", y) //y的結果由協程1和2競爭決定,協程1在後,則爲2-200,協程2在後則爲3-300
}

在上面的示例中,我們可以看到,打印出來的結果,當讀操作時,x依次被同時傳入協程1和協程2中,進行相應的讀取,但在寫操作時,x又依次進入寫的操作裏,在其中一個寫操作結束後,再進行下一個寫操作;

由此可見,讀寫瑣在進行讀寫操作時,最大的優點是,節約讀的操作時間

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章