go标准库中sync包

sync包有以下几个内容:
(1)sync.Pool 临时对象池
(2)sync.Mutex 互斥锁
(3)sync.RWMutex 读写互斥锁
(4)sync.WaitGroup 组等待
(5)sync.Cond 条件等待
(6)sync.Once 单次执行

一、临时对象池 --- 2019年11月8日20:05更新
1、Pool是用于存储那些被分配了但是没有被使用,而未来可能会使用的值,以减小垃圾回收的压力。
2、Pool是协程安全的,应该用于管理协程共享的变量,不推荐用于非协程间的对象管理
3、调动 New 函数,将使用函数创建一个新对象返回
4、从Pool中取出对象时,如果Pool中没有对象,将执行New(),如果没有对New进行赋值,则返回Nil。
5、先放入的后出来,和栈类似
Pool一个比较好的例子是fmt包,fmt包总是需要使用一些[]byte之类的对象,golang建立了一个临时对象池,存放着这些对象,如果需要使用一个[]byte,就去Pool里面拿,如果拿不到就分配一份。这比起不停生成新的[]byte,用完了再等待gc回收来要高效得多

type Pool struct {
        // 创建临时对象的函数
        New func() interface{}
}

// 向临时对象池中存入对象
func (p *Pool) Put() x interface{}

// 向临时对象池中取出对象
func (p *Pool) Get() interface{}

案例:

package main

import (
    "fmt"
    "sync"
)

func main() {
    var pool sync.Pool
    var val interface{}
    pool.Put("1")
    pool.Put(12)
    pool.Put(true)

    for {
        val = pool.Get()
        if val == nil {
            break
        }
        fmt.Println(val)
    }
}

二、互斥锁
互斥锁用来保证在任一时刻,只能有一个协程访问某对象。Mutex的初始值为解锁状态,Mutex通常作为其它结构体的匿名字段使用,使该结构体具有Lock和Unlock方法。
Mutex可以安全的再多个协程中并行使用。

注意:如果对未加锁的进行解锁,则会引发panic。

加锁,保证数据能够正确:

package main

import (
    "fmt"
    "sync"
)

var num int
var mu sync.Mutex
var wg sync.WaitGroup

func main() {
    wg.Add(10000)
    for i := 0; i < 10000; i++ {
        go Add()
    }
    wg.Wait()
    fmt.Println(num)
}

func Add() {
    mu.Lock() // 加锁
    defer func() {
        mu.Unlock() // 解锁
        wg.Done()
    }()

    num++
}

并发没有加锁,如下代码,当你执行下面代码时,会发现结果不等于10000,其原因是因为出现这样的情况,就是其中一些协程刚好读取了num的值,此时该协程刚好时间片结束,被挂起,没有完成加1。然后其他协程进行加1,然后当调度回到原来那个协程,num = 原来的那个num(而不是最新的num) + 1,导致num数据出错:

package main

import (
    "fmt"
    "sync"
)

var num int
var wg sync.WaitGroup

func main() {
    wg.Add(10000)
    for i := 0; i < 10000; i++ {
        go Add()
    }
    wg.Wait()
    fmt.Println(num)
}

func Add() {
    defer wg.Done()
    num++
}

三、读写互斥锁
RWMutex比Mutex多了一个“写锁定” 和 “读锁定”,可以让多个协程同时读取某对象。RWMutex的初始值为解锁状态。RWMutex通常作为其它结构体的匿名字段使用。
RWMutex可以安全的在多个协程中并行使用。

// Lock 将 rw 设置为写状态,禁止其他协程读取或写入
func (rw *RWMutex) Lock()

// Unlock 解除 rw 的写锁定状态,如果rw未被锁定,则该操作会引发 panic。
func (rw *RWMutex) Unlock()

// RLock 将 rw 设置为锁定状态,禁止其他协程写入,但可以读取。
func (rw *RWMutex) RLock()

// Runlock 解除 rw 设置为读锁定状态,如果rw未被锁定,则该操作会引发 panic。
func (rw *RWMutex) RUnLock()

// RLocker 返回一个互斥锁,将 rw.RLock 和 rw.RUnlock 封装成一个 Locker 接口。
func (rw *RWMutex) RLocker() Locker

四、组等待
WaitGroup 用于等待一组协程的结束。主协程在创建每个子协程的时候先调用Add增加等待计数,每个子协程在结束时调用 Done 减少协程计数。之后,主协程通过 Wait 方法开始等待,直到计数器归零才继续执行。

// 计数器增加 delta,delte可以时负数
func (wg *WaitGroup) Add(delta int)

// 计数器减少1,等价于Add(-1)
func (wg *WaitGroup) Done()

// 等待直到计数器归零。如果计数器小于0,则该操作会引发 panic。
func (wg *WaitGroup) Wait()

五、条件等待
条件等待和互斥锁有不同,互斥锁是不同协程公用一个锁,条件等待是不同协程各用一个锁,但是wait()方法调用会等待(阻塞),直到有信号发过来,不同协程是共用信号

package main

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

func main() {
    var wg sync.WaitGroup
    cond := sync.NewCond(new(sync.Mutex))

    for i := 0; i < 3; i++ {
        go func(i int) {
            fmt.Println("协程", i, "启动。。。")
            wg.Add(1)
            defer wg.Done()
            cond.L.Lock()
            fmt.Println("协程", i, "加锁。。。")
            cond.Wait()
            fmt.Println("协程", i, "解锁。。。")
            cond.L.Unlock()
        }(i)
    }
    time.Sleep(2e9)
    fmt.Println("主协程发送信号量。。。")
    cond.Signal()

    time.Sleep(2e9)
    fmt.Println("主协程发送信号量。。。")
    cond.Signal()

    time.Sleep(2e9)
    fmt.Println("主协程发送信号量。。。")
    cond.Signal()
    wg.Wait()
}

六、单次执行
Once的作用是多次调用但只执行一次,Once只有一个方法,Once.Do(),向Do传入一个函数,这个函数在第一次执行Once.Do()的时候会被调用,以后再执行Once.Do()将没有任何动作,即使传入了其他的函数,也不会被执行,如果要执行其它函数,需要重新创建一个Once对象。
Once可以安全的再多个协程中并行使用。是协程安全的

标准库中原型:
// 多次调用仅执行一次指定的函数f
func (o *Once) Do(f func())

// 示例:Once
package main

import (
    "fmt"
    "sync"
)

func main() {
    var once sync.Once
    var wg sync.WaitGroup

    onceFunc := func() {
        fmt.Println("hello")
    }
    wg.Add(10)
    for i := 0; i < 10; i++ {
        go func() {
            defer wg.Done()
            once.Do(onceFunc) // 多次调用只执行一次
        }()
    }
    wg.Wait()
}

参考:
(1)https://www.cnblogs.com/golove/p/5918082.html
(2)https://blog.csdn.net/wangshubo1989/article/details/77966432?locationNum=9&fps=1

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容

  • 更多精彩文章:https://deepzz.com Desc:Go sync 包的使用方法,sync.Mutex,...
    deepzz阅读 1,965评论 3 9
  • sync包使用官方文档:http://devdocs.io/go/sync/index#Map Go中sync包包...
    DDY26阅读 1,470评论 0 1
  • 一个sync.Pool对象就是一组临时对象的集合。Pool是协程安全的。Pool用于存储那些被分配了但是没有被使用...
    bigtom阅读 21,807评论 17 9
  • 原文:http://developer.android.com/training/sync-adapters/cr...
    tiger桂阅读 458评论 0 0
  • 其实心情蛮忐忑的,不安微微后悔,谈不上后悔吧,总是有一丝的难受。 土豆说要来找我的时候,我有点震惊,她这么懒居然想...
    宋小朝阅读 191评论 0 0