前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go中的同步与锁

Go中的同步与锁

作者头像
李海彬
发布2018-03-27 10:39:17
8580
发布2018-03-27 10:39:17
举报
文章被收录于专栏:Golang语言社区
最近学习了Go语言中同步包中的互斥锁、读写锁、Once、waitGroup。在并发程序开发的过程中,这两种锁是非常重要的,包括对共享资源进行访问控制的时候。sync是Go语言中的标准库。

Mutex 互斥锁

  • 互斥锁是传统并发程序对共享资源进行访问控制的主要手段。是sync包中的Mutex结构体。
    • type Mutex struct {}
  • 该结构体包括了两个方法,可以说是非常简单使用的
    • func (m *Mutex) Lock() {}
    • func (m *Mutex) Unlock() {}
  • 我们通过一个简单的例子来说明他的用法:
代码语言:javascript
复制
package main

import (

	"sync"

	"fmt"

)

type safeCounter struct {

	number int

	sync.Mutex

}

func (sc *safeCounter) Increment() {

	sc.Lock()

	sc.number++

	sc.Unlock()

}

func (sc *safeCounter) Decrement() {

	sc.Lock()

	sc.number--

	sc.Unlock()

}

func (sc *safeCounter) getNumber() int {

	sc.Lock()

	number := sc.number

	sc.Unlock()

	return number

}

func main() {

	sc := new(safeCounter)

	for i := 0; i < 100; i++ {

		go sc.Increment()

		go sc.Decrement()

	}

	fmt.Println(sc.getNumber())

}
  • 上述例子通过互斥锁来保证number整型变量在使用goroutine的情况下,持续稳定地输出0的结果。当然你可以试一下,去掉锁的保护,是否还可以稳定输出0?

RWMutex 读写锁

  • 读写锁是针对读写操作的互斥锁。遵循两个原则即可
    • 可以随便地读,并且支持多个goroutine同时读取
    • 写的时候,既不能读也不能写。
  • RWMutex 提供了四个方法
    • func (*RWMutex) Lock
    • func (*RWMutex) Unlock
    • func (*RWMutex) RLock
    • func (*RWMutex) RUnlock
  • 通过读写map的一个例子来说明RWMutex的使用方法:
代码语言:javascript
复制
package main

import (

	"fmt"

	"math/rand"

	"sync"

	"time"

)

type MapCounter struct {

	m map[int]int

	sync.RWMutex

}

func (mapCounter *MapCounter) Reader(n int) {

	for {

		mapCounter.RLock()

		v := mapCounter.m[rand.Intn(n)]

		mapCounter.RUnlock()

		fmt.Println(v)

		time.Sleep(1 * time.Second)

	}

}

func (mapCounter *MapCounter) Writer(n int) {

	for i := 0; i < n; i++ {

		mapCounter.Lock()

		mapCounter.m[i] = i * 10

		mapCounter.Unlock()

		time.Sleep(1 * time.Second)

	}

}

func main() {

	mc := MapCounter{m: make(map[int]int)}

	go mc.Writer(10)

	go mc.Reader(10)

	go mc.Reader(10)

	time.Sleep(15 * time.Second)

}

Once

  • Once 顾名思义,就是只执行一次 。通过一个简单的例子就可以说明:
代码语言:javascript
复制
package main

import (

	"fmt"

	"sync"

)

func main() {

	once := sync.Once{}

	done := make(chan bool)

	for i := 0; i < 10; i++ {

		go func() {

			once.Do(sayHello)

			done <- true

		}()

	}

	for i := 0; i < 10; i++ {

		fmt.Println(<-done)

	}

}

func sayHello() {

	fmt.Println("Hello")

}
  • 以上的例子只输出了一个“Hello” ,其余的都是true。

WaitGroup

  • WaitGroup 是可以一个goroutine集合,当集合里的goroutine执行完毕后,这个WaitGroup就会自动结束。你可以定义这个WaitGroup的大小。他里面只有三个方法:
    • func (wg *WaitGroup) Add(delta int) {} //定义大小
    • func (wg *WaitGroup) Done() {}
    • func (wg *WaitGroup) Wait() {}
  • 具体用法,通过下面的小例子说明。
代码语言:javascript
复制
package main

import (

	"fmt"

	"sync"

)

func main() {

	wg := sync.WaitGroup{}

	for i := 0; i <= 5; i++ {

		wg.Add(1)

		go func(i int) {

			defer wg.Done()

			fmt.Println("Work done for ", i)

		}(i)

	}

	wg.Wait()

}
  • 建议大家可以把上面的代码都跑一遍,方便自己理解代码的含义。结合官方文档来理解会更加容易。

参考

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-05-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Golang语言社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Mutex 互斥锁
  • RWMutex 读写锁
  • Once
  • WaitGroup
  • 参考
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档