golang并发----基础

Channels

创建channel

使用内置的make函数,我们可以创建一个channel

// ch has type 'chan int'
ch := make(chan int) //  unbuffered channel
ch = make(chan int, 0) // unbuffered channel
ch = make(chan int, 3) // buffered channel with capacity 3

引用类型&零值&比较

  • 和map类似,channel也对应一个make创建的底层数据结构的引用.当我们复制一个channel或用于函数参数传递时,我们只是拷贝了一个channel引用,因此调用者和被调用者将引用同一个channel对象.
  • 和其它的引用类型一样,channel的零值也是nil.
  • 两个相同类型的channel可以使用==运算符比较

发送&接收

一个发送语句将一个值从一个goroutine通过channel发送到另一个执行接收操作的goroutine

ch <- x  // a send statement
x = <-ch // a receive expression in an assignment statement
<-ch     // a receive statement; result is discarded

关闭channel

只有发送者需要关闭通道,接收者永远不会需要关闭通道

  • 如果channel关闭,随后对基于该channel的任何发送操作都将导致panic异常
  • 对一个已经被close过的channel进行接收操作依然可以接受到之前已经成功发送的数据
  • 如果channel中已经没有数据的话将产生一个零值的数据
  • 使用内置的close函数就可以关闭一个channel:close(ch),通常是配合defer使用

其实你并不需要关闭每一个channel.
只有当需要告诉接收者goroutine,所有的数据已经全部发送时才需要关闭channel.
不管一个channel是否被关闭,当它没有被引用时将会被Go语言的垃圾自动回收器回收.

关闭一个channels还会触发一个广播机制
所有channel接收者都会在channel关闭时 立刻从阻塞等待中返回 ok值为false 这个广播机制经常被利用进行向多个订阅者同时发送信号 例如退出信号

不带缓存的Channels(同步channel)

基于无缓存Channels的发送和接收操作将导致两个goroutine做一次同步操作
一个基于无缓存Channels的发送操作将导致发送者goroutine阻塞,直到另一个goroutine在相同的Channels上执行接收操作.
当发送的值通过Channels成功传输之后,两个goroutine可以继续执行后面的语句.
如果接收操作先发生,那么接收者goroutine也将阻塞,直到有另一个goroutine在相同的Channels上执行发送操作.

关于同步&并发
  • 同步
    当我们说x事件在y事件之前发生(happens before),我们并不是说x事件在时间上比y时间更早,我们要表达的意思是要保证在此之前的事件都已经完成了.
    例如在此之前的更新某些变量的操作已经完成,你可以放心依赖这些已完成的事件了
  • 并发
    当我们说x事件既不是在y事件之前发生也不是在y事件之后发生,我们就说x事件和y事件是并发的。这并不是意味着x事件和y事件就一定是同时发生的,我们只是不能确定这两个事件发生的先后顺序.
func main() {
    out := make(chan int)
    // 这里向out发送数据,但是并没有另外一个goroutine来接收out的值
    out <- 2
    go func(in chan int) {
        fmt.Println(<-in)
    }(out)
    // fatal error: all goroutines are asleep - deadlock!
}
消息事件

基于channels发送消息有两个重要方面:

  • 每个消息都有一个有意义的值,channel单纯用来传输数据
  • 有时候希望强调通讯发生的时刻时,我们将它称为消息事件.这些消息事件并不携带额外的信息,它仅仅是用作两个goroutine之间的同步.这时候可以传struct{}/bool/1这种值.
func main() {
    conn, err := net.Dial("tcp", "localhost:8000")
    if err != nil {
        log.Fatal(err)
    }
    done := make(chan struct{})
    go func() {
        io.Copy(os.Stdout, conn) // NOTE: ignoring errors
        log.Println("done")
        done <- struct{}{} // signal the main goroutine
    }()
    mustCopy(conn, os.Stdin)
    conn.Close()
    <-done // wait for background goroutine to finish
}

带缓存的Channels

带缓存的Channel内部持有一个元素队列,队列的最大容量是在调用make函数创建channel时通过第二个参数指定的.
向缓存Channel的发送操作就是向内部缓存队列的尾部插入元素,接收操作则是从队列的头部删除元素.
如果内部缓存队列是满的,那么发送操作将阻塞直到因另一个goroutine执行接收操作而释放了新的队列空间.
如果channel是空的,接收操作将阻塞直到有另一个goroutine执行!!!

串联的Channels(Pipeline)

串联Channels的管道可以用在需要长时间运行的服务中,每个长时间运行的goroutine可能会包含一个死循环,在不同goroutine的死循环内部使用串联的Channels来通信.

检测关闭的channel

如果发送者知道,没有更多的值需要发送到channel的话,那么让接收者也能及时知道没有多余的值可接收将是有用的,因为接收者可以停止不必要的接收等待.在发送方关闭channel即可.
但是在发送方关闭这个channel后,接收方依然会收到一个永无休止的零值序列.

  • if v,ok:=<-ch;!ok{break}
  • for v:=range ch{} // 当channel被关闭并且没有值可接收时跳出循环

goroutines泄漏,和垃圾变量不同,泄漏的goroutines并不会被自动回收.因此确保每个不再需要的goroutine能正常退出是重要的!!!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容