1. Go语言中可以使用sync.WaitGroup来实现并发任务的同步

package main

import (
"fmt"
"sync"
) func hello(wg *sync.WaitGroup) {
defer wg.Done()
fmt.Println("hello")
} func main() {
var wg sync.WaitGroup
wg.Add(1)
//go hello(wg) // 注意:wg是一个结构体,传递的时候需要传递指针,此处传递的结构体,导致wg.Wait()一直等待,死锁
go hello(&wg) wg.Wait()
fmt.Println("main over")
}

  需要注意sync.WaitGroup是一个结构体,传递的时候要传递指针。

2. sync.Once

在编程的很多场景下我们需要确保某些操作在高并发的场景下只执行一次,例如只加载一次配置文件、只关闭一次通道等。

Go语言中的sync包中提供了一个针对只执行一次场景的解决方案–sync.Once。

sync.Once只有一个Do方法

package main

import (
"fmt"
"log"
"net"
"os"
"sync"
)

var printPid sync.Once

func main() {
listener, err := net.Listen("tcp", "127.0.0.1:18888")
if err != nil {
log.Fatalln(err)
return
}
defer listener.Close()

for {
// 注意:无论for循环遍历多少次,此处的Do方法只会执行一次
printPid.Do(func() {
fmt.Println("当前进程的ID是:", os.Getpid())
})

conn, err := listener.Accept()
if err != nil {
log.Fatalln("监听端口错误", err)
}

log.Println(conn.RemoteAddr(), "链接成功")
//go handleConn(conn) // 开启一个goroutine来处理新到来客户端链接
}
}

 sync.Once结构体内部包含了一个互斥锁和布尔值,互斥锁保证布尔值和数据的安全,而布尔值用来记录初始化是否完成,

  这样设计就能保证初始化操作的时候是并发安全的,并且初始化操作也不会被执行多次

 

3. sync.Map

  go语言中内置的map不是并发安全的

package main

import (
"fmt"
"strconv"
"sync"
) var m = make(map[string]int) func get(key string) int {
return m[key]
}
func set(key string, value int) {
m[key] = value
} func main() {
// 内置的map不是并发安全的
wg := sync.WaitGroup{}
for i := 0; i < 5; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
key := strconv.Itoa(i)
set(key, i)
fmt.Printf("key:%v, value:%v\n", key, get(key))
}(i)
}
wg.Wait()
}

上面的代码开启少量几个goroutine的时候可能没什么问题,当并发多了之后执行上面的代码就会报fatal error: concurrent map writes错误。

像这种场景下就需要为map加锁来保证并发的安全性了,Go语言的sync包中提供了一个开箱即用的并发安全版map–sync.Map。开箱即用表示不用像内置的map一样使用make函数初始化就能直接使用。同时sync.Map内置了诸如Store、Load、LoadOrStore、Delete、Range等操作方法。

package main

import (
"fmt"
"strconv"
"sync"
) func main() {
// go语言的sync包提供了开箱即用的并发安全的map-sync.Map,
// 开箱即用表示不用向内置的map一样使用make函数来初始化就能直接使用
var (
m = sync.Map{}
wg sync.WaitGroup
) for i := 0; i < 20; i++ {
wg.Add(1)
go func(i int) {
key := strconv.Itoa(i)
m.Store(key, i) // map赋值
v, _ := m.Load(key)
fmt.Printf("key:%v, value:%v\n", key, v) defer wg.Done()
}(i)
} wg.Wait() }

  

golang中的sync的更多相关文章

  1. golang中并发sync和channel

    golang中实现并发非常简单,只需在需要并发的函数前面添加关键字"go",但是如何处理go并发机制中不同goroutine之间的同步与通信,golang 中提供了sync包和channel ...

  2. 【记录一个问题】golang中使用sync.Pool反而造成了负优化

    之前有这样的代码:从http收数据后,进行snappy解码: dst := make([]byte, 0, len(httpRequestData)*5) dst, err = snappy.Deco ...

  3. golang 中 sync包的 WaitGroup

    golang 中的 sync 包有一个很有用的功能,就是 WaitGroup 先说说 WaitGroup 的用途:它能够一直等到所有的 goroutine 执行完成,并且阻塞主线程的执行,直到所有的 ...

  4. golang中sync.RWMutex和sync.Mutex区别

    golang中sync包实现了两种锁Mutex (互斥锁)和RWMutex(读写锁),其中RWMutex是基于Mutex实现的,只读锁的实现使用类似引用计数器的功能. type Mutex     f ...

  5. golang 中 sync.Mutex 的实现

    mutex 的实现思想 mutex 主要有两个 method: Lock() 和 Unlock() Lock() 可以通过一个 CAS 操作来实现 func (m *Mutex) Lock() { f ...

  6. Golang中WaitGroup使用的一点坑

    Golang中WaitGroup使用的一点坑 Golang 中的 WaitGroup 一直是同步 goroutine 的推荐实践.自己用了两年多也没遇到过什么问题.直到一天午睡后,同事扔过来一段奇怪的 ...

  7. golang中Context的使用场景

    golang中Context的使用场景 context在Go1.7之后就进入标准库中了.它主要的用处如果用一句话来说,是在于控制goroutine的生命周期.当一个计算任务被goroutine承接了之 ...

  8. golang中锁mutex的实现

    golang中的锁是通过CAS原子操作实现的,Mutex结构如下: type Mutex struct {     state int32                     sema  uint ...

  9. 【协作式原创】查漏补缺之Golang中mutex源码实现(预备知识)

    预备知识 CAS机制 1. 是什么 参考附录3 CAS 是项乐观锁技术,当多个线程尝试使用 CAS 同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是 ...

随机推荐

  1. c++ vector释放概述

    这里仅为概述,具体的详情分析,可以Google下,会得到更详尽的解释. 1.函数clear和erase都将数组的size清空,但对应的空间并没有回收,而且,一直push_baclk, 对应的capac ...

  2. 【LeetCode】263. Ugly Number 解题报告(Java & Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 除去2,3,5因子 日期 [LeetCode] 题目 ...

  3. 【九度OJ】题目1017:还是畅通工程 解题报告

    [九度OJ]题目1017:还是畅通工程 解题报告 标签(空格分隔): 九度OJ 原题地址:http://ac.jobdu.com/problem.php?pid=1017 题目描述: 某省调查乡村交通 ...

  4. 【LeetCode】721. Accounts Merge 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地址: https://leetcode.com/problems/accounts ...

  5. 【剑指Offer】链表中环的入口结点 解题报告(Python)

    [剑指Offer]链表中环的入口结点 解题报告(Python) 标签(空格分隔): 剑指Offer 题目地址:https://www.nowcoder.com/ta/coding-interviews ...

  6. Chapter 7 Confounding

    目录 7.1 The structure of confounding Confounding and exchangeability Confounding and the backdoor cri ...

  7. 从源码看全局异常处理器@ExceptionHandler&@ExceptionHandler的生效原理

    1.开头在前 日常开发中,几乎我们的项目都会用到异常处理器,我们通常会定制属于自己的异常处理器,来处理项目中大大小小.各种各样的异常.配置异常处理器目前最常用的方式应该是使用@ControllerAd ...

  8. element 表格只展开一行(点击下一行上一行关闭)

    源码:第一步 <el-table :data="tableData" border :row-class-name="tableRowClassName" ...

  9. Vue.js高效前端开发 • 【Ant Design of Vue框架进阶】

    全部章节 >>>> 文章目录 一.栅格组件 1.栅格组件介绍 2.栅格组件使用 3.实践练习 二.输入组件 1.输入框组件使用 2.选择器组件使用 3.单选框组件使用 4.实践 ...

  10. SpringCloud发现服务代码(EurekaClient,DiscoveryClient)

    1.说明 本文介绍SpringCloud发现服务代码的开发, 通过使用EurekaClient,DiscoveryClient来发现注册中心的服务等, 从而可以自定义客户端对注册中心的高级用法. 2. ...