设为首页 加入收藏

TOP

在 Go 语言中,正确的使用并发(二)
2014-11-24 00:08:11 来源: 作者: 【 】 浏览:20
Tags:言中 正确 使用 并发
相同的问题。并发执行或不幸的上下文切换意味着我们可能以负平衡结束。幸运的是,内部的事件循环理念应用在这里同样很好,甚至更好,因为事件循环 goroutine 可以与每个个人账户结构实例很好的耦合。这里有一个例子说明这一点:


type Account struct {
balance float64
deltaChan chan float64
balanceChan chan float64
errChan chan error
}



func NewAccount(balance float64) (a *Account) {
a = &Account{
balance: balance,
deltaChan: make(chan float64),
balanceChan: make(chan float64),
errChan: make(chan error),
}
go a.run()
return
}


func (a *Account) Balance() float64 {
return <-a.balanceChan
}


func (a *Account) Deposit(amount float64) error {
a.deltaChan <- amount
return <-a.errChan
}


func (a *Account) Withdraw(amount float64) error {
a.deltaChan <- -amount
return <-a.errChan
}


func (a *Account) applyDelta(amount float64) error {
newBalance := a.balance + amount
if newBalance < 0 {
return errors.New("Insufficient funds")
}
a.balance = newBalance
return nil
}


func (a *Account) run() {
var delta float64
for {
select {
case delta = <-a.deltaChan:
a.errChan <- a.applyDelta(delta)
case a.balanceChan <- a.balance:
// Do nothing, we've accomplished our goal w/ the channel put.
}
}
}


这个API略有不同,Deposit 和 Withdraw 方法现在都返回了错误。它们并非直接处理它们的请求,而是把账户余额的调整量放入 deltaChan,在 run 方法运行时的事件 环中访问 deltaChan。同样的,Balance 方法通过阻塞不断地在事件循环中请求数据,直到它通过 balanceChan 接收到一个值。


须注意的要点是上述的代码,所有对结构内部数据值得直接访问和修改都是有事件循环触发的 *within* 代码来完成的. 如果公共 API 调用表现良好并且只使用给出的渠道同数据进行交互的话, 那么不管对公共方法进行多少并发的调用,我们都知道在任意给定的时间只会有它们之中的一个方法得到处理. 我们的时间循环代码推理起来更加容易了很多.


该模式的核心是 Heke 的设计. 当Heka启动时,它会读取配置文件并且在它自己的go例程中启动每一个插件. 随着时钟信号、关闭通知和其它控制信号,数据经由通道被送入插件中. 这样就鼓励了插件作者使用一种想上述事例那样的 事件循环类型的架构 来实现插件的功能.


再次,GO不会保护你自己. 写一个同其内部数据管理和主题有争议的条件保持松耦合的Heka插件(或者任何架构)是完全可能的. 但是有一些需要注意的小地方,还有Go的争议探测器的自由应用程序,你可以编写的代码其行为可以预测,甚至在抢占式调度的门面代码中.


相关阅读:


首页 上一页 1 2 下一页 尾页 2/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇OpenCV 实现人脸检测与相关知识整.. 下一篇Zookeeper API JAVA 解析

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: