zoukankan      html  css  js  c++  java
  • go channel

    go channel

    1、不同goroutine之间如何进行通讯?

    • 全局变量和锁同步
    • Channel

    2、channel概念

    • 类似unix中管道(pipe)
    • 先进先出
    • 线程安全,多个goroutine同时访问,不需要加锁
    • channel是有类型的,一个整数的channel只能存放整数

    3、channel声明

    var 变量名 chan 类型

    var test chan int
    var test chan string
    var test chan map[string]string
    var test chan stu
    var test chan *stu
    

    4、channel初始化

    使用make进行初始化

    var test chan int
    test = make(chan int, 10)
    
    var test chan string
    test = make(chan string, 10)
    

    5、channel基本操作

    • 从channel读取数据
    var testChan chan int
    testChan = make(chan int, 10)
    var a int
    a = <- testChan
    
    • 从channel写入数据
    var testChan chan int
    testChan = make(chan int, 10)
    var a int  = 10
    testChan <- a

     channel初始化、基本操作示例:

    package main
    
    import "fmt"
    
    type student struct {
    	name string
    }
    
    func testmap(){
    	var mapChan chan map[string]string
    	mapChan = make(chan map[string]string, 10)
    	m := make(map[string]string, 16)
    	m["stu01"] = "123"
    	m["stu02"] = "456"
    	mapChan <- m
    }
    
    func teststruct(){
    	var structChan chan student
    	structChan = make(chan student, 10)
    
    	stu := student {
    		name: "stu01",
    	}
    
    	structChan <- stu
    }
    
    func teststruct1(){
    	var structChan chan *student
    	structChan = make(chan *student, 10)
    
    	stu := student {
    		name: "stu01",
    	}
    
    	structChan <- &stu
    }
    
    func main() {
    
    	var stuChan chan interface{}
    	stuChan = make(chan interface{}, 10)
    
    	stu := student{name: "stu01"}
    
    	stuChan <- &stu
    
    	var stu01 interface{}
    	stu01 = <-stuChan
    
    	var stu02 *student
    	stu02, ok := stu01.(*student)
    	if !ok {
    		fmt.Println("can not convert")
    		return
    	}
    
    	fmt.Println(stu02)
    }
    

    goroutine和channel相结合示例

    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func write(ch chan int) {
    	for i := 0; i < 100; i++ {
    		ch <- i
    		fmt.Println("put data:", i)
    	}
    }
    
    func read(ch chan int) {
    	for {
    		var b int
    		b = <-ch
    		fmt.Println("get data:", b)
    		time.Sleep(time.Second)
    	}
    }
    
    func main() {
    	intChan := make(chan int, 10)
    	go write(intChan)
    	go read(intChan)
    
    	time.Sleep(100 * time.Second)
    }
    

    6、channel特点

    • channel阻塞
    • 带缓冲区的channel

    如下所示,testChan只能放一个元素:

    var testChan chan int
    testChan = make(chan int)
    var a int
    a = <- testChan
    

    如下所示,testChan是带缓冲区的chan,一次可以放10个元素:

    var testChan chan int
    testChan = make(chan int, 10)
    var a int  = 10
    testChan <- a
    

    7、chan的关闭

    使用内置函数close进行关闭,chan关闭之后,for range遍历chan中 已经存在的元素后结束

    使用内置函数close进行关闭,chan关闭之后,没有使用for range的写法 需要使用,v, ok := <- ch进行判断chan是否关闭

    package main
    
    import "fmt"
    
    func main() {
    	var ch chan int
    	ch = make(chan int, 10)
    
    	for i := 0; i < 10; i++ {
    		ch <- i
    	}
    
    	close(ch)
    	for {
    		var b int
    		b, ok := <-ch
    		if ok == false {
    			fmt.Println("chan is close")
    			break
    		}
    		fmt.Println(b)
    	}
    }
    

    8、channel range

    package main
    
    import "fmt"
    
    func main() {
    	var ch chan int
    	ch = make(chan int, 1000)
    
    	for i := 0; i < 10; i++ {
    		ch <- i
    	}
    
    	close(ch)
    	for v := range ch {
    		fmt.Println(v)
    	}
    }
    

     使用channel关闭,再使用channel range轮询完channel中的值后自动结束。

    9、channel之间同步

    package main
    
    import "fmt"
    
    func send(ch chan int, exitChan chan struct{}) {
    
    	for i := 0; i < 10; i++ {
    		ch <- i
    	}
    
    	close(ch)
    	var a struct{}
    	exitChan <- a
    }
    
    func recv(ch chan int, exitChan chan struct{}) {
    	for {
    		v, ok := <-ch
    		if !ok {
    			break
    		}
    		fmt.Println(v)
    	}
    
    	var a struct{}
    	exitChan <- a
    }
    
    func main() {
    	var ch chan int
    	ch = make(chan int, 10)
    	exitChan := make(chan struct{}, 2)
    
    	go send(ch, exitChan)
    	go recv(ch, exitChan)
    
    	var total = 0
    	for _ = range exitChan {
    		total++
    		if total == 2 {
    			break
    		}
    	}
    }

    结合上述channel所有功能以及结合goroutine代码示例

    package main
    
    import (
    	"fmt"
    )
    
    func calc(taskChan chan int, resChan chan int, exitChan chan bool) {
    	// 素数判断
    	for v := range taskChan {
    		flag := true
    		for i := 2; i < v; i++ {
    			if v%i == 0 {
    				flag = false
    				break
    			}
    		}
    
    		if flag {
    			resChan <- v  // 满足条件的素数放入resChan
    		}
    	}
    
    	fmt.Println("exit")
    	exitChan <- true
    }
    
    func main() {
    	intChan := make(chan int, 1000)
    	resultChan := make(chan int, 1000)
    	exitChan := make(chan bool, 8)
    
    	go func() {
    		for i := 0; i < 10000; i++ {
    			intChan <- i
    		}
    
    		close(intChan)
    	}()
    
    	for i := 0; i < 8; i++ {  // 启动8个goroutine
    		go calc(intChan, resultChan, exitChan)
    	}
    
    	// 等待所有计算的goroutine全部退出
    	go func() {
    		for i := 0; i < 8; i++ {
    			<-exitChan
    			fmt.Println("wait goroute ", i, " exited")
    		}
    		close(resultChan)
    	}()
    
    	for v := range resultChan {
    		fmt.Println(v)
    	}
    }
    

    10、chan的只读和只写

    • 只读chan的声明
    Var 变量的名字 <-chan int
    Var readChan <- chan int
    • 只写chan的声明
    Var 变量的名字 chan<- int
    Var writeChan chan<- int
    

     示例:

    package main
    
    import "fmt"
    
    func send(ch chan<- int, exitChan chan struct{}) {
    
    	for i := 0; i < 10; i++ {
    		ch <- i
    	}
    
    	close(ch)
    	var a struct{}
    	exitChan <- a
    }
    
    func recv(ch <-chan int, exitChan chan struct{}) {
    	for {
    		v, ok := <-ch
    		if !ok {
    			break
    		}
    
    		fmt.Println(v)
    	}
    
    	var a struct{}
    	exitChan <- a
    }
    
    func main() {
    	var ch chan int
    	ch = make(chan int, 10)
    	exitChan := make(chan struct{}, 2)
    
    	go send(ch, exitChan)
    	go recv(ch, exitChan)
    
    	var total = 0
    	for _ = range exitChan {
    		total++
    		if total == 2 {
    			break
    		}
    	}
    }
    

    11、chan进行select操作

    样例一:

    package main
    
    import "fmt"
    import "time"
    
    func main() {
    	var ch chan int
    	ch = make(chan int, 10)
    	ch2 := make(chan int, 10)
    	go func() {
    		var i int
    		for {
    			ch <- i
    			time.Sleep(time.Second)
    			ch2 <- i * i
    			time.Sleep(time.Second)
    			i++
    		}
    	}()
    	for {
    		select {
    		case v := <-ch:
    			fmt.Println(v)
    		case v := <-ch2:
    			fmt.Println(v)
    		default:
    			fmt.Println("get data timeout")
    			time.Sleep(time.Second)
    		}
    	}
    }
    

    样例二:

    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func main() {
    	var ch chan int
    	ch = make(chan int, 1)
    
    	go func() {
    		var i int
    		for {
    			select {
    			case ch <- i:
    			default:
    				fmt.Println("channel is full")
    				time.Sleep(time.Second)
    			}
    
    			i++
    		}
    	}()
    
    	for {
    		v := <-ch
    		fmt.Println(v)
    	}
    }
    
  • 相关阅读:
    JAVA8十大新特性详解
    博客主题
    nideshop小程序商城部署
    Eclipse创建Maven多模块工程Module开发(图文教程)
    将博客搬至CSDN
    腾讯开源软件镜像站上线
    python-应用OpenCV和Python进行SIFT算法的实现
    初学node.js-nodejs中实现删除用户路由
    本博客正在实验姿态捕捉,可以尝试允许摄像头运行
    博客园如何实现看板娘Live2d?来吧少年,开启新世界的大门!——live2d 博客园 个性化定制
  • 原文地址:https://www.cnblogs.com/shhnwangjian/p/7493030.html
Copyright © 2011-2022 走看看