理解Go语言中的通道

1.使用通道

        如果说Goroutine是一种支持并发编程的方式,那么通道就是一种与Goroutine通信的方式。通道让数据能够进入和离开Goroutine,可方便Goroutine之间进行通信。

“不要通过共享内存来通信,而通过通信来共享内存。”

        这句话说明了Go语言并发实现方式的不同之处,这部分有必要做进一步解释。在其他编程语言中,并发编程通常是通过在多个进程或线程之间共享内存实现的。共享内存能够让程序同步,确保程序以合乎逻辑的方式执行。在程序执行过程中,进程或线程可能对共享内存加锁,以禁止其他进程或线程修改它。这合乎情理,因为如果在操作期间共享内存被其他进程修改,可能会带来灾难性后果--引发Bug或导致程序崩溃。通过这种方式给内存加锁,可确保它是独占的--只有一个进程或线程能够访问它。

         这听起来可能太过抽象,我们来看一个例子:两个人持有一个联名帐户,他们同时要从这个帐户支付费用,但这两笔交易的总额超过了帐户余额。如果两个交易同时进行且不加锁,则余额检查可能表明资金充足,但实际上资金不够;然而,如果第一个交易将帐户加锁,则直到交易完成,都可避免这样的情况发生。对于简单的并发而言,这种方式看似合理,但如果联名帐户有20个持有人,且他们经常使用这个帐户进行交易呢?在这种情况下,加锁管理工作或能非常复杂。

        共享内存和锁的管理工作并非那么容易,很多编程语言要求程序员对内存和内存管理有深入认识。即便是久经沙场的程序员也会遇到这样的情形,即为找出进程或线程争用共享内存而引发的Bug,需要花费数天时间。在使用共享内存的并发环境中,如果不能始终知道程序的哪部分将先更新数据,那么将难以推断其中发生的情况。

        虽然使用共享内存有其用武之地,但Go语言使用通道在Goroutine之间收发消息,避免了使用共享内存。严格地说,Goroutine并不是线程,但您可将其视为线程,因为它们能够以非阻塞方式执行代码。在前面关于两人持有一个联合帐户的例子中,如果使用Goroutine,将可能向通道发送一条消息,而通道可能限制后续交易或另一个帐户持有人的行为。通过收发消息,使得能够以推送方式协调并发事件。事件发生时,可将触发的消息推送给接收者。使作共享内存时,程序必须检查共享内存。在变化频繁的并发编程环境中,很多人都认为使用消息是一种更佳的通信方式。

        下列程序使用了Goroutine来执行运行速度缓慢的函数,以免阻塞整个程序的执行。

package main

import (
	"fmt"
	"time"
)

func slowFunc() {
	time.Sleep(time.Second * 2)
	fmt.Println("sleeper() finished")
}

func main() {
	go slowFunc()
	fmt.Println("I am not shown until slowFunc( ) completes")
	time.Sleep(time.Second * 3)
}

程序运行结果如下:

I am not shown until slowFunc( ) completes
sleeper() finished

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mindfulness code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值