【转】关于 Goroutine Channel Select 的用法和理解
原文:https://blog.csdn.net/jfkidear/article/details/88661693
------------------------------------------
关于 Goroutine Channel Select 的用法和理解
阅读 384
收藏 13
2017-05-18
原文链接:blog.sodroid.com
转载请注明本文地址,感谢 :)
了解进程、线程、协程
本文不详细解释这三个名词的意思,下面有一篇文章,不懂的同学可以参考看看。
Goroutine的使用
- Goroutine 奉行通过通信来共享内存,而不是共享内存来通信
- 使用goroutine很简单,只需要用到一个关键字go,我们用一段代码来示例一下如何使用go关键字
- package main
- import (
- "fmt"
- )
- func main() {
- go Goroutine()
- }
- func Goroutine() {
- fmt.Println("Goroutine")
- }
没有输出?
- 执行了上面的代码后,你会发现,什么都没有输出,那么是什么问题呢?
因为我们当前的程序,只是一个单线程的程序,main函数只要执行完毕后,就不会再管其他线程在做什么事情了,程序自动退出。 然后我们想到了一个办法,加一个sleep函数,让main函数等待Goroutine函数执行完毕后再退出。
更改后的代码如下:
- package main
- import (
- "fmt"
- "time"
- )
- func main() {
- go Goroutine()
- time.Sleep(3 * time.Second)
- }
- func Goroutine() {
- fmt.Println("Goroutine")
- }
- 不出所料,程序成功打印出了“Goroutine”字符串。
引入Channel
- 通过上面的实验,我们成功地用Goroutine,并打印出了一句话。现在问题来了,这个并不是我们想要的。为什么?如果我的Goroutine函数里的代码需要执行10s、20s甚至更多的时候,怎么办?难道还是继续Sleep更多的秒数吗?
- 我们需要的是,当Goroutine函数执行完毕的时候,自动通知main函数。所以这里我们就引出了channel
创建方式
channel使用make创建
chann := make(chan bool)
往channel中传入数据
chann <- true
输出channel中的数据
<- chann
接着我们改进上面使用Sleep方式的代码,换成使用channel的版本
- 代码如下:
- package main
- import (
- "fmt"
- )
- func main() {
- chann := make(chan bool)
- go func() {
- fmt.Println("Goroutine")
- chann <- true
- }()
- <- chann
- }
- 如果运行以上的代码片段后,你成功输出了Goroutine,那么说明我们的写法是没错的。现在我们来理解一下这段代码的意思,我们看看匿名函数外面的
<-chann,这实际上是起到了阻塞的作用,当匿名函数里面的业务没有执行完并讲true传入channel中的时候,这个程序是不会退出的,匿名函数外面会一直在等待。当匿名函数里面执行到了chann <- true,也就是将true传入了channel的时候,就不会继续阻塞,这时候程序就会结束。这就是channel的作用。
使用for range迭代输出Channel
- 需要注意的是,当你在对channel 迭代的时候,必须在某个位置明确的关闭这个channel,不然程序就会死锁。我们用一个代码段来示例一下:
- package main
- import (
- "fmt"
- )
- func main() {
- chann := make(chan bool)
- go func() {
- fmt.Println("Goroutine")
- chann <- true
- close(chann) //关闭channel
- }()
- for v := range chann {
- fmt.Println(v)
- }
- }
Channel 的定义类型
- Channel 类型的定义格式:
ChannelType = ("chan" | "chan" "<-" | "<-" "chan")
- Channel包含了三种类型的定义,可选的<-代表的是Channel的方向。没有指定方向的话,Channel就是双向的,既可以接受数据,也可以发送数据。
chan T//可以接收也可以发送chan <- bool//可以发送bool类型的数据<- chan bool//可以接收int类型的数据
无缓冲Channel与缓冲Channel
无缓冲Channel
- 定义方式
chann := make(chan int) - 所谓无缓冲Channel就是在通道中只能传入1个值,若是传入的值一直没有被取走,那么就会一直阻塞着,直到被取走。可以说是同步阻塞的
- 需要注意的是,无缓冲Channel一定是先取后传。当代码中出现了取的操作时,发现Channel里面并没有值,那么就会发生阻塞,当Channel里有值了,才会停止阻塞。
缓冲Channel
- 定义方式
chann := make(chan int,100) - 有缓冲Channel,比如缓冲值是100,那么除非传入的值已经达到了100了,否则这个Channel中,还是可以不断地传值进去。当Channel满了,就会发生阻塞,等值被取走后,才可以继续传值。
如何判断一组任务是否完成
使用缓冲Channel
- package main
- import (
- "fmt"
- "runtime"
- )
- func main() {
- runtime.GOMAXPROCS(runtime.NumCPU()) // 设置线程数为当前计算机的CPU数
- chann := make(chan bool, 10)
- for i := 0; i < 10; i++ {
- go Go(chann, i)
- }
- for i := 0; i < 10; i++ {
- <-chann
- }
- }
- func Go(chann chan bool, index int) {
- a := 1
- for i := 0; i < 100000000; i++ {
- a += 1
- }
- fmt.Println(index, a)
- chann <- true
- }
使用sync包
- 通过设置一个任务组,大小为10。每完成一个任务就记录一次
wg.Done(),当10个任务都完成的时候,程序自动退出。
- package main
- import (
- "fmt"
- "runtime"
- "sync"
- )
- func main() {
- runtime.GOMAXPROCS(runtime.NumCPU())
- wg :=sync.WaitGroup{}
- wg.Add(10)
- for i := 0; i < 10; i++ {
- go Go(&wg, i)
- }
- wg.Wait()
- }
- func Go(wg *sync.WaitGroup, index int) {
- a := 1
- for i := 0; i < 100000000; i++ {
- a += 1
- }
- fmt.Println(index, a)
- wg.Done()
- }
Select
select 用于多个channel监听并收发消息,当任何一个case满足条件则会执行,若没有可执行的case,就会执行default,如果没有default,程序就会阻塞。
- package main
- import (
- "fmt"
- "time"
- )
- func main() {
- chann := make(chan int)
- go enqueue(chann)
- for {
- select {
- case v, ok := <-chann:
- if ok {
- fmt.Println(v)
- } else {
- fmt.Println("close")
- return
- }
- default:
- fmt.Println("waiting")
- }
- }
- }
- func enqueue(chann chan int) {
- time.Sleep(3 * time.Second)
- chann <- 1
- close(chann)
- }
参考
【转】关于 Goroutine Channel Select 的用法和理解的更多相关文章
- Go语言学习笔记(七)杀手锏 Goroutine + Channel
加 Golang学习 QQ群共同学习进步成家立业工作 ^-^ 群号:96933959 Goroutine Go语言的主要的功能在于令人简易使用的并行设计,这个方法叫做Goroutine,通过Gorou ...
- 使用goroutine+channel和java多线程+queue队列的方式开发各有什么优缺点?
我感觉很多项目使用java或者c的多线程库+线程安全的queue数据结构基本上可以实现goroutine+channel开发能达到的需求,所以请问一下为什么说golang更适合并发服务端的开发呢?使用 ...
- HAVING COUNT(*) > 1的用法和理解
HAVING COUNT(*) > 1的用法和理解 作用是保留包含多行的组. SELECT class.STUDENT_CODE FROM crm_class_schedule class GR ...
- golang channel select
尝试多个channel同时触发时,select的表现: package main import ( "fmt" "time" ) func loop(ch ch ...
- GO语言练习:channel select 超时机制
1.代码 2.运行 3.解析 1.代码 package main import ( "time" "fmt" ) func waitFor(ch chan in ...
- 一个Golang例子:for + goroutine + channel
Rob Pike 在 Google I/O 2012 - Go Concurrency Patterns 里演示了一个例子(daisy chain). 视频地址:https://www.youtube ...
- golang并发编程goroutine+channel(一)
go语言的设计初衷除了在不影响程序性能的情况下减少复杂度,另一个目的是在当今互联网大量运算下,如何让程序的并发性能和代码可读性达到极致.go语言的并发关键词 "go" go dos ...
- go14--并发concurrency,Goroutine ,channel
package main /** 并发concurrency 很多人都是冲着 Go 大肆宣扬的高并发而忍不住跃跃欲试,但其实从 源码的解析来看,goroutine 只是由官方实现的超级“线程池”而已. ...
- goroutine,channel
Go语言中有个概念叫做goroutine, 这类似我们熟知的线程,但是更轻. 以下的程序,我们串行地去执行两次loop函数: package main import "fmt" f ...
随机推荐
- 【miscellaneous】 GStreamer应用开发手册学习笔记之基础概念介绍
第3章. 基础概念介绍 本章将介绍GStreamer的基本概念. 理解这些概念对于你后续的学习非常重要,因为后续深入的讲解我们都假定你已经完全理解了这些概念. 3.1. 元件(Elements) 元件 ...
- PHP 7 错误处理 Error
前提:PHP 7 改变了大多数错误的报告方式.不同于 PHP 5 的传统错误报告机制,现在大多数错误被作为 Error 异常抛出. try { echo 2 % 0; // 错误: 分母为0 } ca ...
- java23种设计模式之八: 工厂方法模式
定义: 定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中.这满足创建型模式中所要求的“创建与使用相分离”的特点. 我们把被创建的对象称为“产品”,把创建产品的对象称为“工 ...
- 【ZOJ】4012 Your Bridge is under Attack
[ZOJ]4012 Your Bridge is under Attack 平面上随机n个点,然后给出m条直线,问直线上有几个点 \(n,m \leq 10^{5}\) 由于共线的点不会太多,于是我们 ...
- TCP状态转换(图解+文字解说)
<深入分析 javaweb 技术内幕>P38 读书扩展 作者:淮左白衣 写于2018年4月12日20:58:36 目录 TCP状态转换图解 图解三次握手 文字讲解三次握手: 图解四次挥手 ...
- 经典排序算法及总结(python实现)
目录 1.排序的基本概念和分类 排序的稳定性: 内排序和外排序 影响内排序算法性能的三个因素: 根据排序过程中借助的主要操作,可把内排序分为: 按照算法复杂度可分为两类: 2.冒泡排序 BubbleS ...
- Centos7.3安装nexus12.1
nexus.12.1-01的安装 1.下载nexus 2.上传到服务器/root/ 3.解压 t ...
- 剑指offer(5)——从尾到头打印链表
题目: 输入一个链表的头结点,从尾到头反过来打印出每个结点的值.结点定义如下: public class ListNode { int val; ListNode next = null; ListN ...
- MySQL 使用tee记录语句和输出日志
在mysql命令行中,使用tee命令,可以记录语句和输出到指定文件.在debugging时会很有用.每执行一条语句,mysql都会讲执行结果刷新到指定文件.Tee功能只在交互模式生效. mysql&g ...
- Oracle数据库导出txt格式工具sqlload2使用
开发需求:需要在数据库中查询数据,最终得到cxv表格形式数据. 使用plsql导出70M数据量非常慢,本次使用sqlload2工具,导出文本txt文本格式. 1)导出txt文本文件$ ./sqluld ...