go channel

go channel

一、不一樣goroutine之間如何進行通信?安全

  • 全局變量和鎖同步
  • Channel

二、channel概念函數

  • 相似unix中管道(pipe)
  • 先進先出
  • 線程安全,多個goroutine同時訪問,不須要加鎖
  • channel是有類型的,一個整數的channel只能存放整數

三、channel聲明spa

var 變量名 chan 類型線程

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

四、channel初始化unix

使用make進行初始化blog

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

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

五、channel基本操做ip

  • 從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初始化、基本操做示例:get

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

六、channel特色string

  • 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

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

八、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中的值後自動結束。

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

 

十、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
		}
	}
}

 

十一、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)
	}
}
相關文章
相關標籤/搜索