GlyphLefkowitz最近写了一篇启蒙文章,文中详细解释了开发高并发软件的一些挑战。如果你开发软件但没有读过这个问题,那么我建议你读一读。这是一篇非常好的文章,现代软件工程应有的丰富智慧。从多个花絮中提取,但如果我冒昧地总结要点,它是这样的:抢占式多任务处理和一般共享状态的结合导致软件开发过程中无法管理的复杂性,开发人员可能更愿意保留一些他们自己的理智这避免了这种难以控制的复杂性。抢占式调度适用于真正的并行任务,但当多个并发线程共享可变状态时,更需要显式多任务协作。尽管协作式多任务处理,您的代码仍然可能很复杂,只是有机会使复杂性保持在可控范围内。当控制权转移明确时,代码阅读器至少有一些明显的迹象表明事情可能会偏离轨道。没有清楚地标记每个新阶段是一个潜在的地雷:“如果这个操作不是原子的,最后会发生什么?”然后每个命令之间的空间变成了一个无尽的空间黑洞,可怕的Heisenbugs出现在过去的这些年里,尽管Heka(一种高性能数据、日志和指标处理引擎)的工作主要是使用GO开发的语言。Go的亮点之一是该语言本身具有一些非常有用的并发原语。但是Go的并发性能如何,需要从支持本地推理的鼓励代码的角度来看。并非所有事实都是好的。所有的Goroutines都访问同一个共享内存空间,状态默认是可变的,但是Go的调度器在上下文选择时不保证准确性。在单核设置中,Go的运行时属于“隐式协同工作”类别,在Glyph中经常提到的异步程序模型列表中选择4。当Goroutine可以在多核系统上并行运行时,事情就不可预测了。Go不可能保护你,但这并不意味着你不能采取措施保护自己。通过在编写代码的过程中使用Go提供的一些原语,可以最大限度地减少相关抢占式调度带来的异常行为。请看下面Glyph例子的“账户转换”代码段中的Go接口(忽略最后那些不易存储定点小数的浮点数)funcTransfer(amountfloat64,payer,payee*Account,serverSomeServerType)error{ifpayer.Balance()a.balance{log.Println("Insufficientfunds")return}log.Printf("withdrawing:%f",amount)a.balance-=amount}不幸的是,这代码遇到与我们最初的Transfer实现相同的问题。并发执行或不幸的上下文切换意味着我们最终可能会出现负余额。幸运的是,内部事件循环的想法在这里也适用,如果不是更好的话,因为事件循环goroutine可以很好地与每个单独的帐户结构实例耦合。这里有一个例子来说明这一点:run()return}func(a*Account)Balance()float64{return<-a.balanceChan}func(a*Account)Deposit(amountfloat64)error{a.deltaChan<-amountreturn<-a.errChan}func(a*账户)取款(amountfloat64)错误{a.deltaChan<--amountreturn<-a.errChan}func(a*账户)applyDelta(amountfloat64)错误{newBalance:=a.balance+amountifnewBalance<0{returnerrors.New("Insufficientfunds")}a.balance=newBalancereturnil}func(a*Account)run(){vardeltafloat64for{select{casedelta=<-a.deltaChan:a.errChan<-a.applyDelta(delta)casea.balanceChan<-a.balance://Donothing,we'veaccomplishedourgoalw/thechannelput.}}}此API略有不同,Deposit和Withdraw方法现在返回错误。他们没有直接处理他们的请求,而是将账户余额的调整放入deltaChan,在run方法的事件循环中访问。同样,Balance方法通过阻塞在事件循环中不断请求数据,直到它通过balanceChan接收到一个值。主要需要注意的是,在上面的代码中,所有对结构内部数据的直接访问和修改都是由事件循环触发的*within*代码完成的。如果公共API调用行为良好并且只使用给定的通道与数据交互,那么无论对公共方法进行多少次并发调用,我们都知道在任何给定时间只会处理其中一个。我们的时间循环代码更容易推理。这种模式的核心是Heke的设计。当Heka启动时,它会读取配置文件并在其自己的go例程中启动每个插件。数据与时钟信号、关机通知和其他控制信号一起通过通道。成插件。这鼓励插件作者使用如上例所示的事件循环类型架构来实现插件功能。同样,GO不会保护自己。编写一个在条件下保持松散耦合的Heka插件(或任何架构)是完全可能的。但是有一些小警告,通过免费应用Go的争议检测器,您可以编写行为可预测的代码,即使是在抢占式调度的门面代码中。英文原文:SaneConcurrencywithGo翻译链接:http://www.oschina.net/translate/sane-concurrency-with-go