专栏首页Golang语言社区在 Go 语言中,正确的使用并发

在 Go 语言中,正确的使用并发

Glyph Lefkowitz最近写了一篇启蒙文章,其中他详细的说明了一些关于开发高并发软件的挑战,如果你开发软件但是没有阅读这篇问题,那么我建议你阅读一篇。这是一篇非常好的文章,现代软件工程应该拥有的丰富智慧。

从多个花絮中提取,但是如果我斗胆提出主要观点的总结,其内容就是:抢占式多任务和一般共享状态结合导致软件开发过程不可管理的复杂性, 开发人员可能更喜欢保持自己的一些理智以此避免这种不可管理的复杂性。抢占式调度对于哪些真正的并行任务是好的,但是当可变状态通过多并发线程共享时,明确的多任务合作更招人喜欢 。

尽管合作多任务,你的代码仍有可能是复杂的,它只是有机会保持可管理下一定的复杂性。当控制转移是明确一个代码阅读者至少有一些可见的迹象表明事情可能脱离正轨。没有明确标记每个新阶段是潜在的地雷:“如果这个操作不是原子操作,最后出现什么情况?”那么在每个命令之间的空间变成无尽的空间黑洞,可怕的Heisenbugs出现

在过去的一年多,尽管在Heka上的工作(一个高性能数据、日志和指标处理引擎)已大多数使用GO语言开发。Go的亮点之一就是语言本身有一些非常有用的并发原语。但是Go的并发性能怎么样,需要通过支持本地推理的鼓励代码镜头观察。

type transfer struct {
        payer *Account
        payee *Account
        amount float64
    }
 
    var xferChan = make(chan *transfer)
    var errChan = make(chan error)
    func init() {
        go transferLoop()
    }
 
    func transferLoop() {
        for xfer := range xferChan {
            if xfer.payer.Balance < xfer.amount {
                errChan <- errors.New("Insufficient funds")
                continue
            }
            log.Printf("%s has sufficient funds", xfer.payer)
            xfer.payee.Deposit(xfer.amount)
            log.Printf("%s received payment", xfer.payee)
            xfer.payer.Withdraw(xfer.amount)
            log.Printf("%s made payment", xfer.payer)
            errChan <- nil
        }
    }
 
    func Transfer(amount float64, payer, payee *Account,
        server SomeServerType) error {
 
        xfer := &transfer{
            payer: payer,
            payee: payee,
            amount: amount,
        }
 
        xferChan <- xfer
        err := <-errChan
        if err == nil  {
            server.UpdateBalances(payer, payee) // Still magic.
        }
        return err
    }
func Transfer(amount float64, payer, payee *Account,
        server SomeServerType) error {
 
        if payer.Balance() < amount {
            return errors.New("Insufficient funds")
        }
        log.Printf("%s has sufficient funds", payer)
        payee.Deposit(amount)
        log.Printf("%s received payment", payee)
        payer.Withdraw(amount)
        log.Printf("%s made payment", payer)
        server.UpdateBalances(payer, payee) // Assume this is magic and always works.
        return nil
    }
type Account struct {
        balance float64
    }
 
    func (a *Account) Balance() float64 {
        return a.balance
    }
 
    func (a *Account) Deposit(amount float64) {
        log.Printf("depositing: %f", amount)
        a.balance += amount
    }
 
    func (a *Account) Withdraw(amount float64) {
        log.Printf("withdrawing: %f", amount)
        a.balance -= amount
    }
type Account struct {
        balance float64
        deltaChan chan float64
        balanceChan chan float64
        errChan chan error
    }

须注意的要点是上述的代码,所有对结构内部数据值得直接访问和修改都是有事件循环触发的 *within* 代码来完成的. 如果公共 API 调用表现良好并且只使用给出的渠道同数据进行交互的话, 那么不管对公共方法进行多少并发的调用,我们都知道在任意给定的时间只会有它们之中的一个方法得到处理. 我们的时间循环代码推理起来更加容易了很多.该模式的核心是 Heke 的设计. 当Heka启动时,它会读取配置文件并且在它自己的go例程中启动每一个插件. 随着时钟信号、关闭通知和其它控制信号,数据经由通道被送入插件中. 这样就鼓励了插件作者使用一种想上述事例那样的 事件循环类型的架构 来实现插件的功能.再次,GO不会保护你自己. 写一个同其内部数据管理和主题有争议的条件保持松耦合的Heka插件(或者任何架构)是完全可能的. 但是有一些需要注意的小地方,还有Go的争议探测器的自由应用程序,你可以编写的代码其行为可以预测,甚至在抢占式调度的门面代码中.

本文分享自微信公众号 - Golang语言社区(Golangweb)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2016-08-17

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 在 Go 语言中,如何正确的使用并发

    从多个花絮中提取,但是如果我斗胆提出主要观点的总结,其内容就是:抢占式多任务和一般共享状态结合导致软件开发过程不可管理的复杂性, 开发人员可能更喜欢保持自己的一...

    李海彬
  • 【Go 语言社区】在 Go 语言中,如何正确的使用并发

    Glyph Lefkowitz最近写了一篇启蒙文章,其中他详细的说明了一些关于开发高并发软件的挑战,如果你开发软件但是没有阅读这篇问题,那么我建议你阅读一篇。这...

    李海彬
  • 在 Go 语言中,如何正确的使用并发

    Glyph Lefkowitz最近写了一篇启蒙文章,其中他详细的说明了一些关于开发高并发软件的挑战,如果你开发软件但是没有阅读这篇问题,那么我建议你阅读一篇。这...

    李海彬
  • 我的第一个 60k+ Star开源项目—JavaGuide

    人生总有各种各样的巧合发生。在 1 年多前,换句话说就是我还是大三的一名学生的时候。我开源了 JavaGuide ,直接到今天 JavaGuide 已经达到现在...

    macrozheng
  • 基于ssm的客户管理系统

    一个简单的客户关系管理系统 管理用户的基本数据 客户的分配 客户的流失 已经客户的状态

    C you again 的博客
  • “大数据+定制化服务”或将引领高端旅游市场

    “严格意义上的高端,可以用以下几个关键字来定义:高端的硬件标准、管家服务、高私密性、稀缺资源、高度细分。” ——知乎用户 高端出境游,核心并不在高价奢华,而让旅...

    企鹅号小编
  • Android 自定义View中的onMeasure onLayout onDraw

    Android自定义View时常重写三个方法onMeasure和onLayout以及onDraw。

    剑行者
  • Docker的集群实战之Swarm模式

    随着业务规模的扩大,一台机器的Docker已经无法满足我们的要求,为了保证性能和高可用,Docker提供了一种叫Swarm的解决方案。

    机智的程序员小熊
  • 数据开放┃欧盟:循序渐进开放政府数据 公共事业受益良多

    腾讯研究院研究员  卢依   对于数据开放政策,欧盟将其定义为“对公共数据的再利用”,即将本由政府和公共机构所产生,收集或者付费获得的数据开放给公众再次使...

    腾讯研究院
  • Android vs iOS:未曾停息的强强对决

    前言: 近期,各种安全事件层出不穷,难以平抚内心浮躁的人们,不妨静下心来品读这篇文章,一位外国朋友对“iOS vs Android”综合的分析。难得一见的对两大...

    FB客服

扫码关注云+社区

领取腾讯云代金券