16.4Go语言干货-并发编程之锁

1. 并发安全与锁

当多个goroutine同时操作有个资源的时候容易出现数据不安全(竟态问题)

举个栗子

package main

import (
	"fmt"
	"sync"
)

var n int //定义一个整数,初始值为0
var wg sync.WaitGroup

func add() {
	defer wg.Done()
	for i := 0; i < 1000000; i++ {
		n += 1
	}
	
}
func main() {
	wg.Add(3)
	go add()
	go add()
	go add()
	wg.Wait()
	fmt.Println(n)

}

每次出现的结果不一样,出现竟态问题!

2. 互斥锁

如何解决数据竟态问题?
在同一时刻只能有一个groutine能对数据进行修改

Go语言中使用sync包中的Mutex类型来实现互斥锁。
示例如下:

package main

import (
	"fmt"
	"sync"
)

var n int //定义一个整数,初始值为0
var wg sync.WaitGroup
var lock sync.Mutex

func add() {
	defer wg.Done()
	for i := 0; i < 1000000; i++ {
		lock.Lock() // 加锁
		n += 1
		lock.Unlock() // 解锁
	}

}
func main() {
	wg.Add(3)
	go add()
	go add()
	go add()
	wg.Wait()
	fmt.Println(n)

}

加上锁以后同一时刻只能由一个goroutine修改数据,保证了数据安全,但是降低了效率

3.读写互斥锁

学习读写互斥锁之前明白一个小概念,我们对数据的操作无非两种,一种是读操作,一种是写操作。

在工作中读操作的频率是远远大于写操作的。

在之前使用的互斥锁是完全锁,部分读写都加上锁,Go语言提供的一种优化方法。对加锁进行读写分离。不限制读操作,只限制写操作。

读写互斥锁在Go语言中使用sync包中的RWMutex类型。

package main

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

var n int
var wg sync.WaitGroup
// var lock sync.Mutex
var rwlock sync.RWMutex

func read() {
	defer wg.Done()
	// lock.Lock() // 加互斥锁
	rwlock.RLock() // 加读锁
	time.Sleep(time.Millisecond)
	// lock.Unlock() // 释放互斥锁
	rwlock.RUnlock() // 释放读锁
}
func write() {
	defer wg.Done()
	// lock.Lock()
	rwlock.Lock() // 加写锁
	n += 1
	time.Sleep(time.Millisecond * 50)
	// lock.Unlock()
	rwlock.Unlock() // 释放写锁
}

func main() {
	start := time.Now()

	for i := 0; i < 10000; i++ {
		go read()
		wg.Add(1)
	}
	for i := 0; i < 10; i++ {
		go write()
		wg.Add(1)
	}
	wg.Wait()
	now := time.Now().Sub(start)
	fmt.Println(now)
}

读写互斥锁适合读多写少的场景,如果读写频率相差不打,读写锁的优势很难发挥出来

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值