zoukankan      html  css  js  c++  java
  • golang学习笔记之channel

    1.声明与初始化

    func main() {
    	// 声明 var 变量名 chan 数据类型
    	var c chan int
    
    	fmt.Printf("chan c : %v
    ", c)
    
    	// 初始化 make(chan 数据类型 [, int])
    	c = make(chan int)
    	fmt.Printf("chan c : %v
    ", c)
    	time.Sleep(time.Second * 5)
    
    	// 也可以这样声明和初始化
    	//ch := make(chan string, 2)
    	//ch <- "hello"
    	//ch <- "world"
    	//s1 := <-ch
    	//s2 := <-ch
    	//fmt.Println(s1, s2)
    }
    

      

      

    2.入队 出队

    var a chan int

    入队:  a <- 100

    出队: data := <- a

    3.无缓冲区channel

    初始化make时不指定容量.即: 

    func main() {
    	// 声明 var 变量名 chan 数据类型
    	var c chan int
    
    	fmt.Printf("chan c : %v
    ", c)
    
    	// 初始化一个无缓冲区channel
    	c = make(chan int)
    	fmt.Printf("chan c : %v
    ", c)
    	time.Sleep(time.Second * 5)
    }
    

      

    无缓冲区channel只有在读取的时候才能写入值

    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func produce(c chan int) {
    	c <- 1000
    }
    
    func consume(c chan int) {
    	data := <-c
    	fmt.Printf("data : %v
    ", data)
    }
    
    func main() {
    	// 声明 var 变量名 chan 数据类型
    	var c chan int
    
    	fmt.Printf("chan c : %v
    ", c)
    
    	// 初始化无缓冲区channel
    	c = make(chan int)
    
    	// 写入channel
    	go produce(c)
    
    	// 消费(读取)channel
    	go consume(c)
    
    	time.Sleep(time.Second * 5)
    }
    

      

    如果注释掉 go consume(c), 那么将没有消费(读取)channel,程序就会一直阻塞直到主线程结束.(如下节:阻塞channel)

    当有go consume(c)进行消费(读取)时,才能写入并读取出channel的值

    4.阻塞channel

    func main() {
    	var a chan int
    	if a == nil {
    		fmt.Println("channel is nil, going to define it")
    		a = make(chan int)
    		a <- 10 //将一直阻塞在这里
    		fmt.Printf("Type of a is : %T", a)
    	}
    }
    

      

    带缓冲区与不带缓冲区 区别举例:

    1.不带缓冲区:面对面签收快递.无收件人取件时(读取),快递员死等(阻塞,除非主线程结束,如下班)

    2.带缓冲区:快递员将包裹存放在柜中(如蜂巢,柜子的数量就是缓冲的容量)

    5.使用channel对goroutine进行同步  

    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func hello(c chan bool) {
    	time.Sleep(time.Second * 5)
    	fmt.Println("只有当我执行后,主线程才能退出哦!")
    	c <- true
    }
    
    func main() {
    	var exitChan chan bool
    	exitChan = make(chan bool)
    	go hello(exitChan)
    	// 只有当子线程中的 channel写入值之后,下面才能读取.否则将一直阻塞
    	<-exitChan
    	fmt.Println("主线程结束")
    }
    

    6.单向channel

    var a chan<- int //只写

    var b <-chan int //只读

    7.关闭channel

    close(c)

    8.判断关闭及遍历channel数据

    a.使用ok判断并使用for循环遍历channel

    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func hello(c chan bool) {
    	time.Sleep(time.Second * 5)
    	fmt.Println("只有当我执行后,主线程才能退出哦!")
    	c <- true
    }
    
    func main() {
    	var exitChan chan bool
    	exitChan = make(chan bool)
    	go hello(exitChan)
    	// 只有当子线程中的 channel写入值之后,下面才能读取.否则将一直阻塞
    	<-exitChan
    	fmt.Println("主线程结束")
    }
    

      

    b.使用 for range遍历-----推荐方式(自动判断是否关闭)

    package main
    
    import "fmt"
    
    func produce(c chan int) {
    	for i := 0; i < 10; i++ {
    		c <- i
    	}
    	close(c)
    }
    
    func main() {
    	ch := make(chan int)
    	go produce(ch)
    
    	// 使用for range 对channel数据遍历
    	for v := range ch {
    		fmt.Println("接收数据: ", v)
    	}
    }
    

      

    9.带缓冲区channel

    package main
    
    import "fmt"
    
    func main() {
    	var ch chan string
    	ch = make(chan string, 3)
    
    	ch <- "hello"
    	ch <- "world"
    	ch <- "!"
    
    	//先入先出
    	s1 := <-ch
    	s2 := <-ch
    	s3 := <-ch
    	fmt.Println(s1, s2, s3)
    }
    

    注:channel空或者满 都会阻塞

    10.使用waitgroup等待一组goroutine结束(sync.WaitGroup)

    原理:计数.  1.起一个goruntine时计数加一 2.执行完一个gorutine时计数减一 3.当计数为0时结束 

    package main
    
    import (
    	"fmt"
    	"sync"
    	"time"
    )
    
    func process(i int, wg *sync.WaitGroup) {
    	fmt.Println("started gorutine ", i)
    	time.Sleep(time.Second * 2)
    	fmt.Printf("goruntine %d ended 
    ", i)
    	wg.Done() //执行完waitgroup计数减一
    }
    
    func main() {
    	// 场景: 需要一组gorutine都执行完 才退出
    	var wg sync.WaitGroup
    	no := 10
    	for i := 0; i < no; i++ {
    		wg.Add(1) //起一个gorutine时 计数加一
    		go process(i, &wg)
    	}
    	wg.Wait() //当计数为0时 等待结束
    	fmt.Println("All go runtines finished executing")
    }
    

      

  • 相关阅读:
    angularjs 中使用 service 在controller 之间 share 对象和数据
    angularjs 中实现 load more 功能
    MVC 中对返回的 data 进行压缩
    linq中如何合并多个predicate条件
    mysql安装常见问题
    Ehcache的CacheManager的使用
    Java Web开发——Filter过滤器
    Java Web开发——Servlet监听器
    JSP内置对象
    JSP指令与动作
  • 原文地址:https://www.cnblogs.com/yin5th/p/9201406.html
Copyright © 2011-2022 走看看