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)
	}
}

 

posted @ 2017-09-08 09:40  shhnwangjian  阅读(351)  评论(0编辑  收藏  举报