zoukankan      html  css  js  c++  java
  • 使用案例大白话讲解Go语言并发编程go chan select close

    使用案例大白话讲解Go语言并发go chan select close

    1、初识Go并发-go关键字实现多线程

    使用go 关键字可以开辟一个新的协程(线程)线程之间并行执行

    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func  printData(data string)  { //循环打印数据
    	for i:=0;i<5;i++{
    		time.Sleep(time.Second)
    		fmt.Println(data,":",i)//打印数据
    	}
    }
    
    
    func main()  {
    
    	printData("主程序")  //函数调用
    	//主程序打印完了才会到下面的协程执行
    	go  printData("子程序1") //多线程的并发
    	go  printData("子程序2")
    	go func(msg  string) {fmt.Println(msg)}("子程序3 Go!Go!Go!")//匿名函数风格
    
    	//主程序一旦执行结束,子程序都会结束,所以这里睡10秒
    	time.Sleep(time.Second*10)
    }
    
    运行结果如下:
    主程序 : 0
    主程序 : 1
    主程序 : 2
    主程序 : 3
    主程序 : 4
    子程序3 Go!
    子程序1 : 0
    子程序2 : 0
    子程序2 : 1
    子程序1 : 1
    子程序1 : 2
    子程序2 : 2
    子程序2 : 3
    子程序1 : 3
    子程序1 : 4
    子程序2 : 4
    

    2、协程与协程之间的通信chan的使用

    package main
    
    import "fmt"
    
    func main()  {
    	messages:=make(chan string) //创建了一个通道。
    
    	go func() {messages<-"Hello Chan!!"}()//发送数据给通道
    
    	fmt.Println(messages) //消息通道内存地址
    
    	msg:=<-messages  //从通道里面拿出字符串赋值给msg
    
    	fmt.Println(msg)  
    
    	messages2:=make(chan string,2)//通道接收多个消息,通道返回结果,2表示通道一次可以容纳2条消息
    	messages2<-"hello baby" //往通道里面放值
    	messages2<-"hello Golang"
    	fmt.Println(<-messages2)
    	fmt.Println(<-messages2)
    }
    
    
    执行结果如下:
    0xc000100060
    Hello Chan!!
    hello baby
    hello Golang
    

    3、使用协程与通道实现同步

    package main
    
    import "fmt"
    import "time"
    
    func worker(done chan bool){
    	fmt.Println("开始干活")
    	time.Sleep(time.Second*3) //干活
    	fmt.Println("活干完了")
    
    	done<-true  //返回数据,我们干完活了
    }
    
    
    
    func main()  {
    	done := make(chan bool, 1) //创建一个通道,传递数据
    	go worker(done) //用done接收消息
    	<-done //锁住,一直等待下去,直到接受到结果
    	fmt.Println("game over")
    }
    
    执行结果如下:
    开始干活
    活干完了
    game over
    
    

    4、实现简单的通信线路

    package main
    import "fmt"
    
    //一个参数发送,一个参数用于接收
    func send(sendStrings chan string, msg string)  {
    	sendStrings<-msg //将msg放到发送的通道中
    }
    
    //一个参数发送,一个参数用于接收
    func receive(sendStrings  chan string,receiveString chan string)  {
    	msg := <-sendStrings
    	receiveString <-msg
    }
    func main() {
    	sendChan := make(chan  string ,1)
    	receiveChan := make(chan  string ,1)//两个通道
    
    	send(sendChan,"发送一个消息:你好Chan")//调用
    	receive(sendChan,receiveChan)
    	fmt.Println(<-receiveChan)//显示通信
    
    }
    执行结果如下:
    发送一个消息:你好Chan
    

    5、select的使用

    简单的介绍select的使用

    package main
    
    import (
    	"fmt"
    )
    
    func main(){
    	var  c1,c2,c3 chan int
    	var  i1,i2 int
    	c1 = make(chan int,1)
    	c1 <- 10
    	c3 = make(chan int,1)
    	c3 <- 30
    	//select 类似于switch语句,case满足条件即可执行
    	//注意 select 的 case 如果同一时间有多个条件满足,会从满足的条件中随机一个执行,
    	//例如以下例子偶尔执行结果是 received 30 from c3 偶尔结果是 received 10 from  c1
    	select{
    		case i1 = <- c1:
    			fmt.Println("received",i1,"from  c1")
    		case c2 <- i2:
    			fmt.Println("send",i2,"to  c2")
    		case i3,ok := (<- c3):
    			if ok{
    				fmt.Println("received",i3,"from c3")
    			}else {
    				fmt.Println("c3 is  closed")
    			}
    		default:
    			fmt.Println("no  communication")
    	}
    	//time.Sleep(time.Second*3)
    }
    
    

    6、关于select的简单的例子

    package main
    
    import "fmt"
    import "time"
    
    func main() {
    	c1:=make(chan string) //选择两个通道
    	c2:=make(chan string)
    	go func() {
    		time.Sleep(time.Second*3) //3秒
    		c1<-"第一条信息"
    	}()
    	go func() {
    		time.Sleep(time.Second*2) //2秒
    		c2<-"第二条信息"
    	}()
    	//如果将此处的for循环中的2改为3会报一个错误"fatal error: all goroutines are asleep - deadlock!"
    	//因此go语言会监测通道的生命周期 当协程执行结束不会有新信息往通道里面扔数据了那么goroutines 就会 asleep(睡眠)
    	for  i:=0;i<2;i++{
    		select{
    			case msg1:= <-c1:
    				fmt.Println("received",msg1)
    			case msg2:=<-c2:
    				fmt.Println("received",msg2)
    
    		}
    		fmt.Println("over!")
    	}
    }
    
    执行结果如下:
    received 第二条信息
    over!
    received 第一条信息
    over!
    
    

    7、select模拟实现访问超时案例

    package main
    
    import "fmt"
    import "time"
    
    func main(){
    	c1:=make(chan  string,1)//传递消息的通道
    	go func() {
    		time.Sleep(time.Second*2) //更改这里的值可以查看不同的效果
    		c1<-"结果  num one"
    		}()
    	select {
    		case res:= <-c1:
    			fmt.Println(res)
    		case  <-time.After(time.Second*3):
    			fmt.Println("timeout 1")
    	}
    
    }
    
    

    8、select实现阻塞与非阻塞接收信息

    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func main()  {
    	messages :=make(chan string)
    	signals:=make(chan bool)
    
    	//非阻塞接收,有可以用就直接用,没有就默认,不等待
    	fmt.Println("程序开始执行...")
    	go func() {
    		time.Sleep(time.Second*2)
    		messages<-"结果  num one"
    	}()
    	
    	//如果存在default 那么就是非阻塞 有可以用就直接用,没有就默认,不等待。
    	//如果将下面的default语句块注释,那么select会等待接收messages中的值。
    	select {
    		case msg:= <-messages:
    			fmt.Println("A 收到消息",msg)
    		default:
    			fmt.Println("C 没有消息收到")
    
    	}
    
    	msg:="hi baby"
    	select {
    		case messages<-msg:
    			fmt.Println("B sent message",msg)
    		default:
    			fmt.Println("B no message sent")
    	}
    
    	select {
    		case msg:= <-messages:
    			fmt.Println("C收到消息",msg)
    		case sig := <-signals:
    			fmt.Println("C收到消息",sig)
    		default:
    			fmt.Println("C no  activity")
    	}
    }
    
    

    9、通道关闭 close

    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func main() {
    	jobs :=make(chan int,5) //通道,返回结果数据
    	done:=make(chan bool)//通道
    	go func() {
    		for {
    			j,ok:= <-jobs
    			//fmt.Printf("ok的类型为%T
    ",ok) //ok的类型为bool 当通道关闭ok的类型为false
    			if ok{
    				fmt.Println("收到工作",j)
    			} else {
    				fmt.Println("收到全部工作结果")
    				done <- true  //其实这里放true和false都无所谓
    			}
    		}
    	}()
    	for j:=1;j<=3;j++{
    		time.Sleep(time.Second)
    		jobs<-j
    		fmt.Println("sent  job",j)
    	}
    	close(jobs)
    	fmt.Println("发送完毕")
    	//等待工作
    	<-done
    }
    
    执行结果如下:
    sent  job 1
    收到工作 1
    收到工作 2
    sent  job 2
    sent  job 3
    发送完毕
    收到工作 3
    收到全部工作结果
    收到全部工作结果
    

    10、简单实战之工作池

    package main
    
    import "fmt"
    import "time"
    //程序目的:雇了三个工人给我打工,我发布工作,三个工人抢着干活。干完了把结果返回给我。jobs相当于是工作池
    //工作协程,两个通道,
    //id编号,jobs工作编号,result  结果
    //其实worker(id int,jobs<-chan int,result chan <-int) 中的<-都可以去掉 你也可以写成worker(id int,jobs chan int,result chan int)
    func worker(id int, jobs chan int, result chan int)  {
    	for j:=range jobs{
    		fmt.Println("worker",id,"开始干活",j)
    		time.Sleep(time.Second)
    		fmt.Println("worker",id,"结束干活",j)
    		result <- j*10
    	}
    }
    
    
    func main() {
    	jobs := make(chan int,100) //工作
    	result := make(chan int,100)//结果
    	//开启三个工作协程序,
    	for w:=1; w<=3;w++{
    		go worker(w,jobs,result)
    	}
    	for j:=1;j<=5;j++{
    		jobs<-j //发布五个工作
    	}
    	close(jobs)//关闭jobs通道。
    
    	for i:=1;i<=5;i++{
    		fmt.Println("result:",<-result)
    	}
    }
    
    程序执行结果:
    worker 3 开始干活 1
    worker 2 开始干活 3
    worker 1 开始干活 2
    worker 1 结束干活 2
    worker 1 开始干活 4
    result: 20
    worker 3 结束干活 1
    worker 2 结束干活 3
    worker 2 开始干活 5
    result: 10
    result: 30
    worker 1 结束干活 4
    result: 40
    worker 2 结束干活 5
    result: 50
    
    
  • 相关阅读:
    windows10装机小记
    Linus Benedict Torvalds hate FUD
    营销文章good
    商城趣聊4
    商城趣聊3
    商城趣聊2
    商城趣聊1
    temp
    学习代码检视方法 (摘自某图片)
    xilinx sdk闪退问题
  • 原文地址:https://www.cnblogs.com/xwxz/p/14500475.html
Copyright © 2011-2022 走看看