go中channel简单使用

su_sai · · 2080 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

channel是go语言在语言级别提供的goroutine间的通信机制。我们可以使用channel在两个或者多个goroutine之间传递信息。channel是进程内的通信。

channel分为带缓冲的以及不带缓冲的。

ch:=make(chan int )创建一个不带缓冲的channel。ch:=make(chan int,2,5)创建一个带缓冲的channel,其中len(ch)是2,cap(ch)是5.

1.不带缓冲的channel使用:

package main

import (
"fmt"
"time"
)

func main() {
ch := make(chan int)
go ff(ch)
fmt.Println("1", time.Now())
ch <- 2
fmt.Println("2", time.Now())
fmt.Println("main end")
fmt.Println("5", time.Now())
}

func ff(ch chan int) {
fmt.Println("3", time.Now())
time.Sleep(2 * time.Second)
<-ch
fmt.Println("ff end")
fmt.Println("4", time.Now())
}

输出:

1 2016-05-12 12:50:02.4098584 +0800 CST
3 2016-05-12 12:50:02.4118585 +0800 CST
ff end
4 2016-05-12 12:50:04.4149731 +0800 CST
2 2016-05-12 12:50:04.4149731 +0800 CST
main end

5 2016-05-12 12:50:04.4149731 +0800 CST

根据时间可以分析一下程序的工作流程。首先main函数运行到ch<-2时候就阻塞了。不带缓冲的channel接收数据后会阻塞,直到从这个channel中读取数据后,阻塞的程序才恢复。等到ff函数运行到<-ch后,main函数才继续运行。这是ff函数也在运行。从打印的时间可以看出两个函数是并发的。


package main


import (
"fmt"
"time"
)


func main() {
ch := make(chan int)
go ff(ch)
fmt.Println("1", time.Now())
<-ch
fmt.Println("2", time.Now())
fmt.Println("main end")
fmt.Println("5", time.Now())
}


func ff(ch chan int) {
fmt.Println("3", time.Now())
time.Sleep(2 * time.Second)
ch <- 2
fmt.Println("ff end")
fmt.Println("4", time.Now())
}

输出: 1 2016-05-12 13:03:00.3583545 +0800 CST
3 2016-05-12 13:03:00.3603546 +0800 CST
ff end
4 2016-05-12 13:03:02.3634692 +0800 CST
2 2016-05-12 13:03:02.3634692 +0800 CST
main end
5 2016-05-12 13:03:02.3634692 +0800 CST

根据打印的时间信息可以分析,main函数在执行到<-ch时,阻塞。不带缓冲的channel从中读取数据时会阻塞,直到向其中写入数据,阻塞的程序才会继续执行。


2.带缓冲的channel使用:

package main


import (
"fmt"
"time"
)


func main() {
ch := make(chan int, 2)
go ff(ch)
fmt.Println("1", time.Now())
ch <- 2
fmt.Println("2", time.Now())
fmt.Println("main end")
fmt.Println("5", time.Now())
}


func ff(ch chan int) {
fmt.Println("3", time.Now())
time.Sleep(2 * time.Second)
<-ch
fmt.Println("ff end")
fmt.Println("4", time.Now())
}

输出:1 2016-05-12 13:07:27.0666093 +0800 CST
2 2016-05-12 13:07:27.0716096 +0800 CST
main end
5 2016-05-12 13:07:27.0716096 +0800 CST

根据打印信息可以分析,main函数在执行到ch<-2的时候,没有阻塞,而是继续执行。那么为什么ff函数没有来得及运行fmt.Println("3", time.Now())这条程序呢?

从上面不带channel的程序可以看出,fmt.Println("3", time.Now())这句话运行的时间比fmt.Println("1", time.Now())这句话运行的时间要晚。晚多少时间和cpu有关。我们可以先不管。可以做出假设,ff函数里面的fmt.Println("3", time.Now())还没来得及执行,main函数就执行完了,程序就退出了。在这个过程中开的goroutine都不会执行,直接取消。

那么,怎么证明上面那段程序ff没有执行是因为main结束了呢?可以在mian函数最后等待一小会。

修改上面的程序如下:

package main

import (
"fmt"
"time"
)

func main() {
ch := make(chan int, 2)
go ff(ch)
fmt.Println("1", time.Now())
ch <- 2
fmt.Println("2", time.Now())
fmt.Println("main end")
fmt.Println("5", time.Now())
time.Sleep(1 * time.Second)
}

func ff(ch chan int) {
fmt.Println("3", time.Now())
time.Sleep(2 * time.Second)
<-ch
fmt.Println("ff end")
fmt.Println("4", time.Now())
}

程序输出:1 2016-05-12 13:17:44.0658997 +0800 CST
2 2016-05-12 13:17:44.0708999 +0800 CST
main end
5 2016-05-12 13:17:44.0708999 +0800 CST
3 2016-05-12 13:17:44.0678998 +0800 CST

可以看到,main最后等待了一秒时间,然后ff函数来得及执行fmt.Println("3", time.Now())。但是在ff函数执行time.Sleep(2 * time.Second)等待两秒的时候,mian已经结束了。

更改一下channel读取和写入的顺序,如下:

package main

import (
"fmt"
"time"
)

func main() {
ch := make(chan int, 2)
go ff(ch)
fmt.Println("1", time.Now())
<-ch
fmt.Println("2", time.Now())
fmt.Println("main end")
fmt.Println("5", time.Now())


}

func ff(ch chan int) {
fmt.Println("3", time.Now())
time.Sleep(2 * time.Second)
ch <- 2
fmt.Println("ff end")
fmt.Println("4", time.Now())
}

输出:1 2016-05-12 13:20:06.0520208 +0800 CST
3 2016-05-12 13:20:06.055021 +0800 CST
ff end
4 2016-05-12 13:20:08.0571355 +0800 CST
2 2016-05-12 13:20:08.0571355 +0800 CST
main end
5 2016-05-12 13:20:08.0571355 +0800 CST

根据打印信息可以分析,main函数在执行到<-ch这句话是阻塞,带缓冲的channel如果里面没有数据,从中读取的话会阻塞程序的运行。等到ff函数执行到ch <- 2时,main函数才从阻塞中恢复。


有疑问加站长微信联系(非本文作者)

本文来自:CSDN博客

感谢作者:su_sai

查看原文:go中channel简单使用

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2080 次点击  
加入收藏 微博
1 回复  |  直到 2000-01-01 00:00:00
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传