Go语言并发编程(一)

引言

Go语言最吸引人的地方是它内建的并发支持。Go并发编程核心的CSP理论的核心概念只有一个:同步通信。

首先明确一个概念:并发不是并行。并发更关注的是程序的设计层面,并发的程序完全是可以顺序执行的,只有在真正的多喝CPU上才可能真正地同时运行。并行更关注的是程序的运行层面,并行一般是简单的大量重复,例如,GPU中对图像处理都会有大量的并行运算。

在并发编程中,对共享资源的正确访问需要精确地控制,在目前绝大多数语言中,都是通过加锁等线程同步方案来解决这一困难,而Go语言却另辟蹊径,它将共享的值通过通道传递。在任意给定的时刻,最好只有一个Goroutine能够拥有该资源。数据竞争从设计层面上就被杜绝了。为提倡这种思考方式,Go语言将其并发编程哲学化为一句口号:“不要通过共享内存来通信,而应通过通信来共享内存。”(Do not communicate by sharing memory; instead, share memory by communicating.)

并发版本的“Hello, World”

func main() {
    done := make(chan int, 1) // 带缓存通道

    go func(){
        fmt.Println("你好,世界")
        done <- 1
    }()

    <-done
}

对于带缓存的通道,对通道的第K个接收完成操作发生在第K+C个发送操作完成之前,其中C是通道的缓存大小。虽然通道是带缓存的,但是main线程接收完成是在后台线程发送开始但还未完成的时刻,此时打印工作也是已经完成的。

基于带缓存通道,我们可以很容易将打印线程扩展到N个。

func main() {
    done := make(chan int, 10) // 带10个缓存

    // 开N个后台打印线程
    for i:= 0; i < cap(done); i++ {
        go func(){
            fmt.Println("你好,世界")
            done <- 1
        }()
    }

    // 等待N个后台线程完成
    for i := 0; i < cap(done); i++ {
        <- done
    }
}

对于这种要等待N个线程完成后再进行下一步的同步操作有一个简单的做法,就是使用sync.WaitGroup来等待一组事件:

func main() {
    var wg sync.WaitGroup

    // 开N个后台打印线程
    for i := 0; i < 10; i++ {
        wg.Add(1)

        go func() {
            fmt.Println("你好,世界")
            wg.Done()
        }()
    }

    // 等待N个后台线程完成
    wg.Wait()
}

其中,wg.Add(1)用于增加等待事件的个数,必须确保在后台线程启动之前执行(如果放到后台线程之中执行则不能保证被正常执行到)。当后台线程完成打印工作之后,调用wg.Done()表示完成一个事件。main()函数的wg.Wait()是等待全部的事件完成。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值