在前面的例子中,我们用互斥锁进行了明确的锁定来让共享的state 跨多个 Go 协程同步访问。另一个选择是使用内置的 Go协程和通道的的同步特性来达到同样的效果。这个基于通道的方法和 Go 通过通信以及 每个 Go 协程间通过通讯来共享内存,确保每块数据有单独的 Go 协程所有的思路是一致的。

Example:

package main
import (
"fmt"
"math/rand"
"sync/atomic"
"time"
)
//在这个例子中,state 将被一个单独的 Go 协程拥有。
// 这就能够保证数据在并行读取时不会混乱。
// 为了对 state 进行读取或者写入,其他的 Go 协程将发送一条数据到拥有的 Go协程中,
// 然后接收对应的回复。结构体 readOp 和 writeOp封装这些请求,并且是拥有 Go 协程响应的一个方式。 type readOp struct {
key int
resp chan int
}
type writeOp struct {
key int
val int
resp chan bool
}
func main() {
// 和前面一样,我们将计算我们执行操作的次数。 var ops int64
// reads 和 writes 通道分别将被其他 Go 协程用来发布读和写请求。 reads := make(chan *readOp)
writes := make(chan *writeOp)
// 这个就是拥有 state 的那个 Go 协程,和前面例子中的map一样,
// 不过这里是被这个状态协程私有的。这个 Go 协程反复响应到达的请求。
// 先响应到达的请求,然后返回一个值到响应通道 resp 来表示操作成功(或者是 reads 中请求的值) go func() {
var state = make(map[int]int)
for {
select {
case read := <-reads:
read.resp <- state[read.key]
case write := <-writes:
state[write.key] = write.val
write.resp <- true
}
}
}()
// 启动 100 个 Go 协程通过 reads 通道发起对 state 所有者Go 协程的读取请求。
// 每个读取请求需要构造一个 readOp,发送它到 reads 通道中,并通过给定的 resp 通道接收结果。 for r := 0; r < 100; r++ {
go func() {
for {
read := &readOp{
key: rand.Intn(5),
resp: make(chan int)}
reads <- read
<-read.resp
atomic.AddInt64(&ops, 1)
}
}()
}
// 用相同的方法启动 10 个写操作。 for w := 0; w < 10; w++ {
go func() {
for {
write := &writeOp{
key: rand.Intn(5),
val: rand.Intn(100),
resp: make(chan bool)}
writes <- write
<-write.resp
atomic.AddInt64(&ops, 1)
}
}()
}
// 让 Go 协程们跑 1s。 time.Sleep(time.Second)
// 最后,获取并报告 ops 值。 opsFinal := atomic.LoadInt64(&ops)
fmt.Println("ops:", opsFinal)
}

Result:

$ go run example.go
ops: 637568

运行这个程序显示这个基于 Go 协程的转台管理的例子达到了每秒大约 600,000 次操作

在这个特殊的例子中,基于 Go 协程的比基于互斥锁的稍复杂。这在某些例子中会有用,

例如,在你有其他通道包含其中或者当你管理多个这样的互斥锁容易出错的时候。你应该使用最自然的方法,特别是关于程序正确性的时候。

坐标: 上一个例子    下一个例子

最新文章

  1. hdu-1179-二分图最大匹配
  2. 十三、File Translator怎么写
  3. jQuery的ajax问题
  4. paip.数组以及集合的操作uapi java php python总结..
  5. php中的字符串常用函数(三) str_replace() 子字符串替换
  6. mac gcc 编译错误 基础问题
  7. 【转】如何在 Windows 中执行干净启动
  8. python全栈开发-Day6 字符编码
  9. Django框架教程之正则表达式URL误区详解
  10. Windows启动配置数据(BCD)存储文件包含一些无效信息
  11. du 查看文件大小
  12. DataGuard之Apply Services(redo应用和SQL应用)
  13. java 日期Date类型比较大小
  14. e778. 在JList中加入和删除项
  15. GMM 模型需不需归一化问题
  16. Lua中获取table长度
  17. Sublime text代码补全插件(支持Javascript、JQuery、Bootstrap框架)
  18. SQL端通过脚本判断文件夹是否存在 并创建
  19. 关于引脚复用,不得不提的GPIO_Pin_sources 和GPIO_Pin
  20. app发布证书、真机调试证书、测试证书、推送证书详细过程

热门文章

  1. Django中如何将javascript中的变量传给位于javascript内的{% url %}中的参数?
  2. service pom
  3. 英语单词debug
  4. list列表切片方法汇总
  5. Angular:自定义表单控件
  6. Power Strings POJ - 2406
  7. [CSP-S模拟测试97]题解
  8. css浮动现象及清除浮动的方法
  9. laravel5.6 ORM 关联模型,一对一和一对多
  10. oracle sql查询表外键关系