设为首页 加入收藏

TOP

GO语言之channel(二)
2017-09-30 13:52:51 】 浏览:5328
Tags:语言 channel
lt; 3; i++ { 18 chs[i] = make(chan int) 19 fmt.Println(i, "ForStart") 20 go Count(i, chs[i]) 21 fmt.Println(i, "ForEnd") 22 } 23 24 fmt.Println("Start debug") 25 for num, ch := range chs { 26 fmt.Println(num, "ReadStart") 27 <-ch 28 fmt.Println(num, "ReadEnd") 29 } 30 31 fmt.Println("End") 32 33 //为了使每一步数值全部打印 34 for { 35 if counts == 3 { 36 break 37 } 38 } 39 }

为了看清goroutine执行的步骤和channel的特性,我特意在每一步都做了打印,下面是执行的结果,感兴趣的同学可以自己试试,打印的顺序可能不一样:

  下面我们分析一下这个流程,看看channel在里面的作用。主程序开始:

  打印 "0 ForStart 0 ForEnd" ,表示 i = 0 这个循环已经开始执行了,第一个goroutine已经开始;

  打印 "1 ForStart"、"1 ForEnd"、"2 ForStart"、"2 ForEnd" 说明3次循环都开始,现在系统中存在3个goroutine;

  打印 "Start debug",说明主程序继续往下走了,

  打印 "0 ReadStar"t ,说明主程序执行到for循环,开始遍历chs,一开始遍历第一个,但是因为此时 i = 0 的channel为空,所以该channel的Read操作阻塞;

  打印 "2 WriteStart",说明第一个 i = 2 的goroutine先执行到Count方法,准备写入channel,因为主程序读取 i = 0 的channel的操作再阻塞中,所以 i = 2的channel的读取操作没有执行,现在i = 2 的goroutine 写入channel后下面的操作阻塞;

  打印 "0 WriteEnd",说明 i = 0 的goroutine也执行到Count方法,准备写入channel,此时主程序 i = 0 的channel的读取操作被唤醒;

  打印 "0 WriteEnd" 和 "0 end and echo 0" 说明写入成功;

  打印 "0 ReadEnd",说明唤醒的 i = 0 的channel的读取操作已经唤醒,并且读取了这个channel的数据;

  打印 "0 ReadEnd",说明这个读取操作结束;

  打印 "1 ReadStart",说明 i = 1 的channel读取操作开始,因为i = 1 的channel没有内容,这个读取操作只能阻塞;

  打印 "1 WriteStart",说明 i = 1 的goroutine 执行到Count方法,开始写入channel 此时 i = 1的channel读取操作被唤醒;

  打印 "1 WriteEnd" 和 "1 end and echo 1" 说明 i = 1 的channel写入操作完成;

  打印 "1 ReadEnd",说明 i = 1 的读取操作完成;

  打印 "2 ReadStart",说明 i = 2 的channel的读取操作开始,因为之前已经执行到 i = 2 的goroutine写入channel操作,只是阻塞了,现在因为读取操作的进行,i = 2的写入操作流程继续执行;

  打印 "2 ReadEnd",说明 i = 2 的channel读取操作完成;

  打印 "End" 说明主程序结束。

  此时可能你会有疑问,i = 2 的goroutine还没有结束,主程序为啥就结束了,这正好印证了我们开始的时候说的,主程序是不等待非主程序完成的,所以按照正常的流程我们看不到 i = 2 的goroutine的的完全结束,这里为了看到他的结束我特意加了一个 counts 计算器,只有等到计算器等于3的时候才结束主程序,接着就出现了打印 "2 WriteEnd" 和 "2 end and echo 2"  到此所有的程序结束,这就是goroutine在channel作用下的执行流程。

  上面分析写的的比较详细,耐心看两遍基本上就明白了,主要帮助大家理解channel的写入阻塞和读入阻塞的应用。

 

基本语法

channel的基本语法比较简单, 一般的声明格式是:

1 var ch chan ElementType

定义格式如下:

1 ch := make(chan int)

还有一个最常用的就是写入和读出,当你向channel写入数据时会导致程序阻塞,直到有其他goroutine从这个channel中读取数据,同理如果channel之前没有写入过数据,那么从channel中读取数据也会导致程序阻塞,直到这个channel中被写入了数据为止

1 ch <- value    //写入
2 value := <-ch  //读取

关闭channel

close(ch)

判断channel是否关闭(利用多返回值的方式):

1 b, status := <-ch

带缓冲的channel,说起来也容易,之前我们使用的都是不带缓冲的channel,这种方法适用于单个数据的情况,对于大量的数据不太实用,在调用make()的时候将缓冲区大小作为第二个参数传入就可以创建缓冲的channel,即使没有读取方,写入方也可以一直往channel里写入,在缓冲区被填完之前都不会阻塞。

c := make(chan int, 1024)

单项channel,单向channel只能用于写入或者读取数据。channel本身必然是同时支持读写的,否则根本没法用。所谓的单向channel概念,其实只是对channel的一种使用限制。单向channel变量的声明:

1 var ch1 chan int   // ch1是一个正常的channel
2 var ch2 <-chan int // ch2是单向channel,只用于读取int数据

单项channel的初始化

1 ch3 := make(chan int)
2 ch4 := <-chan int(ch3) // ch4是一个单向的读取channel

 

超时机制

  超时机制其实也是channel的错误处理,channel固然好用,但是有时难免会出现实用错误,当是读取channel的时候发现channel为空,如果没有错误处理,像这种情况就会使整个goroutine锁死了,无法运行,我找了好多资料和说法,channel 并没有处理超时的方法,但是可以利用其它方法间接的处理这个问题,可以使用select机制处理,select的特点比较明显,只要有一个case完成了程序就会往

首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇2016年最新mac下vscode配置golang.. 下一篇golang中如何使用http,socket5代理

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目