控制并发

Go 拥有强大的并发特性,我们该如何控制并发呢?控制并发的场景还是挺常见的,可能我们担心并发数太高对系统产生其他影响。

针对具体的一些场合,我们可以利用 map 数据类型进行并发控制,只要我们固定一定数量的 key 就可以实现。

结合一个实际的例子,我们监控用户在聊天区的内容,比如我们的处理任务只想启动 128 个协程来并发处理这些数据。

①我们可以根据用户的 UID 进行取模运算,我们在处理数据时,首先获取用户 UID 和 128 取模运算后的结果作为 key,然后去 map 中查看 key 是否存在,

②如果 key 不存在,向 map 中写入一条 key 对应的数据。map 中的 value 是一个包含 chan 的数据类型。在写入 chan 数据时,再启动一个协程就专门用来处理这个 chan 中的数据

③如果 key 存在,直接向 map 对应的 vulue 中插入数据

const Shard = 128

type message struct {
	Chan chan int64
}

// 协程的处理逻辑
func (msg *message) Handle() bool {
	<-msg.Chan
	return false
}


// key: int 0<=key<=127 
// value: struct message
var Distribute map[int64]*message

func main() {

	var uid int64 = 123456
	key := uid % Shard

	dst, isOk := Distribute[key]
	if isOk {
		dst.Chan <- uid
	} else {
		Distribute[key] = &message{Chan: make(chan int64, 1)}
		go func() {
			Distribute[key].Handle()
		}()
	}
}

上述的例子,属于发布订阅模式的范畴,不是针对每个处理都启动一个协程去处理,而是固定了 128 个。但这种方式用的可能并不多,很多情况,我们没有一个合适的值去做拆分。

我们还有别的方式,就是借住 channel buffer 的特性,很好理解,还以我们允许 128 个协程为例,我们只需要在创建 chnnel 的时候指定他的缓存空间为 128 即可。

① 在我们并发执行方法前,向 channel 中写入一个 key

② 当我们执行完成方法后,从 channel 中读取一个 key

通过这两个操作来实现控制服务中最多只有 buffer size 个协程在并发运行。

var limitChan = make(chan struct{}, 128)
go func() {
    limitChan <- struct{}{}
    // really  do
    <- limitChan
}

其他的控制并发的方式就不介绍了,但文章的重心并不是上面介绍的两点内容,而是“如何更优雅的 channel 这种控制并发的方式”,我直接上代码了:

type gate chan bool

func (g gate) enter() { g <- true }
func (g gate) leave() { <-g }

简单的几行代码,对上面的 channel 的写法做了抽象。代码的出处是:golang.org/x/tools/godoc/vfs/gatefs

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值