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++使用map保存成员函数地址

    note 本基于c++11介绍一种使用map保存成员函数地址 可避免使用 if 和 switch 配置灵活 方便, 代码维护效率高 结果: 范例开始 头文件包含 #include <iostre ...

  2. 【九度OJ】题目1206:字符串连接 解题报告

    [九度OJ]题目1206:字符串连接 解题报告 标签(空格分隔): 九度OJ http://ac.jobdu.com/problem.php?pid=1206 题目描述: 不借用任何字符串库函数实现无 ...

  3. 【LeetCode】373. Find K Pairs with Smallest Sums 解题报告(Python)

    [LeetCode]373. Find K Pairs with Smallest Sums 解题报告(Python) 标签: LeetCode 题目地址:https://leetcode.com/p ...

  4. GCD(hdu1695)

    GCD Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...

  5. Codeforces 919D:Substring(拓扑排序+DP)

    D. Substring time limit: per test3 seconds memory limit: per test256 megabytes inputstandard: input ...

  6. 设置div背景透明的两种方法

    实现div背景透明的两种方法 1.使用opacity属性 background-color:#000; opacity: 0.5; 这样做可以设置div内部所以区域的透明度,但是也会影响里面的文字,效 ...

  7. Simplicial principal component analysis for density functions in Bayes spaces

    目录 问题 上的PCA Hron K, Menafoglio A, Templ M, et al. Simplicial principal component analysis for densit ...

  8. Spring企业级程序设计作业目录(作业笔记)

    Spring企业级程序设计 • [目录] 第1章 Spring之旅  >>> 1.1.6 使用Eclipse搭建的Spring开发环境,使用set注入方式为Bean对象注入属性值并打 ...

  9. 使用 Eclipse 创建一个静态的登录页面

    要求: 使用 Eclipse 创建一个静态的登录页面 实现步骤: 在 Eclipse 中,点击"File",显示菜单,选择"New" "Other&q ...

  10. 编写Java程序,测试包的使用和成员的访问权限

    返回本章节 返回作业目录 需求说明: 测试包的使用和成员的访问权限: 分别创建两个包,在这两个包下分别建立两个类. 其中某个类的某个方法需要引用用另一个包中某个类的某些成员属性. 被引用成员属性分别使 ...