在前面的例子中,我们用互斥锁进行了明确的锁定来让共享的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 协程的比基于互斥锁的稍复杂。这在某些例子中会有用,

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

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

go语言从例子开始之Example37.Go 状态协程的更多相关文章

  1. go语言学习--内核态和用户态(协程)

    go中的一个特点就是引入了相比于线程更加轻量级的协程(用户态的线程),那么什么是用户态和内核态呢? 一.什么是用户态和内核态 当一个任务(进程)执行系统调用而陷入内核代码中执行时,我们就称进程处于内核 ...

  2. Go语言 进程、线程、轻量级进程、协程和go中的Goroutine 那些事儿

    原文:http://www.cnblogs.com/shenguanpu/archive/2013/05/05/3060616.html 电话面试被问到go的协程,曾经的军伟也问到过我协程.虽然用py ...

  3. 038_go语言中的状态协程

    代码演示: package main import ( "fmt" "math/rand" "sync/atomic" "time ...

  4. 一个“蝇量级” C 语言协程库

    协程(coroutine)顾名思义就是“协作的例程”(co-operative routines).跟具有操作系统概念的线程不一样,协程是在用户空间利用程序语言的语法语义就能实现逻辑上类似多任务的编程 ...

  5. gRPC in ASP.NET Core 3.x -- Protocol Buffer(2)Go语言的例子(下)

    第一篇文章(大约半年前写的):https://www.cnblogs.com/cgzl/p/11246324.html gRPC in ASP.NET Core 3.x -- Protocol Buf ...

  6. go语言从例子开始之Example36.互斥锁

    在前面的例子中,我们看到了如何使用原子操作来管理简单的计数器.对于更加复杂的情况,我们可以使用一个互斥锁来在 Go 协程间安全的访问数据. Example: package main import ( ...

  7. go语言从例子开始之Example35.原子计数器

    Go 中最主要的状态管理方式是通过通道间的沟通来完成的,我们在工作池的例子中碰到过,但是还是有一些其他的方法来管理状态的.这里我们将看看如何使用 sync/atomic包在多个 Go 协程中进行 原子 ...

  8. go语言从例子开始之Example34.速率限制

    速率限制(英) 是一个重要的控制服务资源利用和质量的途径.Go 通过 Go 协程.通道和打点器优美的支持了速率限制. Example: package main import "fmt&qu ...

  9. go语言从例子开始之Example33.工作池

    在这个例子中,我们将看到如何使用 Go 协程和通道实现一个工作池 . Example: package main import "fmt" import "time&qu ...

随机推荐

  1. springboot框架中的各种 注解

    使用注解的优势: 1.采用纯java代码,不在需要配置繁杂的xml文件 2.在配置中也可享受面向对象带来的好处 3.类型安全对重构可以提供良好的支持 4.减少复杂配置文件的同时亦能享受到springI ...

  2. [LeetCode] 53. Maximum Subarray 最大子数组 --动态规划+分治

    Given an integer array nums, find the contiguous subarray (containing at least one number) which has ...

  3. CF576D Flights for Regular Customers 矩阵乘法 + Bitset优化

    %%%cxhscst2's blog Codeforces 576D Flights for Regular Customers(矩阵加速DP) 代码非常优美 + 简洁,学习到了 Code: #inc ...

  4. easyui禁止下拉框

    $("#"+vpcid).combobox({disabled: true}); $("#"+vpcid).combobox('setValue',parent ...

  5. 01.cordova 安装及项目创建

    1.安装cordova cnpm install -g cordova@6.0.0  这里用6.0.0版本,默认下载最新版本,创建项目时候会报错  2.创建项目 cordova create myap ...

  6. Java并发指南14:JUC中常用的Unsafe和Locksupport

    本文转自网络,侵删 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutoria ...

  7. java 中异常类

    算术异常类:ArithmeticExecption 空指针异常类:NullPointerException 类型强制转换异常:ClassCastException 数组负下标异常:NegativeAr ...

  8. MYSQL之union和order by分析([Err] 1221 - Incorrect usage of UNION and ORDER BY)

    我在一个业务中采用了按月的分表策略,当查询的条件跨月的时候,使用了union all汇总2个表的数据,并按插入时间倒序排列.查询并不复杂,但是当执行的时候却报错了. SELECT * FROM `ta ...

  9. maven项目 @Resource报错 ava.lang.NoSuchMethodError: javax.annotation.Resource.lookup()Ljava/lang/String;

    @Resource 出错 java.lang.NoSuchMethodError: javax.annotation.Resource.lookup() maven项目中,使用@Resource报错. ...

  10. cts-on-gsi测试流程

    测试前提: 1.发货user版本 2.selinux:Enable 3.连接ADB,stay awake 4.烧录XXX申请的key 5.外网环境(ipv6) ATV9测试准备(正常准备环境+fast ...