day14 channel通道

了解channel通道

  • 用于 协程(线程间的通信)
  • 一个通道发送和接收数据,默认是 阻塞
  • 声明通道
    • 使用 make 声明通道
    • 使用 var 定义 通道后,在使用make创建通道
  • 不要通过共享内存实现通信,要通过通信实现共享内存
package main

import "fmt"

func main() {
	/* channel
	- 用于 协程(线程间的通信)
	- 一个通道发送和接收数据,默认是 `阻塞`
	- 声明通道
		- 使用 make 声明通道
		- 使用 var 定义 通道后,在使用make创建通道
	- 不要通过共享内存实现通信,要通过通信实现共享内存
	*/

	// 1. 使用make 声明通道
	channel01 := make(chan int)

	// 2. var 声明 通道,
	var channel02 chan bool
	channel02 = make(chan bool)

	go func() {
		for i := 0; i < 10; i++ {
			fmt.Println("goroutine")
		}

		// 2. 往通道里放值 使用 <-
		channel01 <- 10
		channel02 <- true
	}()

	// 3. 当有通道在取值时,默认阻塞
	channelData1 := <-channel01
	channelData2 := <-channel02
	fmt.Println("获取通道1的数据:", channelData1)
	fmt.Println("获取通道2的数据:", channelData2)
}

channel死锁 场景

  • 创建了通道 ,没有写入数据 【死锁】
  • 创建了通道,写入数据,没人接收 【死锁】
  • 两个通道相互依赖 【死锁】 channelA <==> channelB

通道关闭

  • 通道不再发送数据了,就手动关闭
package main

import (
	"fmt"
	"time"
)

func closeChannelFunc(ch chan int) {
	for i := 0; i < 10; i++ {

		ch <- i
	}
	close(ch)
}

func main() {
	/* 通道的关闭
	- 通道不再发送数据了,就手动关闭
	*/

	closeCh := make(chan int)
	go closeChannelFunc(closeCh)
	for {
		time.Sleep(time.Second)
		// ok 判断chan的状态是否关闭。如果关闭了,不会在取值
		data, ok := <-closeCh
		if ok == false {
			fmt.Println("通道已经读取完毕!", ok)
			break
		}
		fmt.Println("正在读取通道中的数据:", data)
	}
}

for 遍历通道

package main

import (
	"fmt"
	"time"
)

func addDataChainFunc(ch chan int) {
	for i := 0; i < 10; i++ {
		ch <- i
		time.Sleep(time.Second)
	}
	close(ch)
}
func main() {
	chan02 := make(chan int)
	go addDataChainFunc(chan02)
	for data := range chan02 {
		fmt.Println("for range 遍历通道数据", data)
	}
}

缓冲通道

  • 遵循:先进先出规则
  • 缓冲通道: 通道又一个参数定义缓冲去,发送数据直到缓冲区填满位置,才会被接受。 只有缓冲区清空才会阻塞
    • 定义: make(chain int , 6)
  • 非缓冲通道: chan 只能存放一个数据,发送和接收都是阻塞。一次发送一次接收
    • 定义: make(chai int , 1) // 默认是:1
package main

import (
	"fmt"
	"strconv"
	"time"
)

func addDataChanFunc(ch chan string) {
	for i := 0; i < 10; i++ {
		ch <- strconv.Itoa(i)
		fmt.Println("子Goroutine 放入数据:", i)
		time.Sleep(time.Second)
	}
	close(ch)
}

func main() {
	/*
		通道
			- 遵循:先进先出规则
			- 缓冲通道:  通道又一个参数定义缓冲去,发送数据直到缓冲区填满位置,才会被接受。 只有缓冲区清空才会阻塞
				- 定义: make(chain int , 6)
			- 非缓冲通道: chan 只能存放一个数据,发送和接收都是阻塞。一次发送一次接收
				- 定义: make(chai int , 1)  // 默认是:1
	*/

	// 非缓冲 通道
	unbufferedChannel := make(chan int)
	fmt.Printf("非缓冲通道:类型:%T 容量:%d 长度:%d \n", unbufferedChannel, cap(unbufferedChannel), len(unbufferedChannel)) //非缓冲通道:类型:chan int 容量:0 长度:0

	// 缓冲通道. 放入数据不会产生死锁。需要等另外的线程来拿数据
	bufferChannel := make(chan string, 5)
	bufferChannel <- "aaa"
	fmt.Printf("缓冲通道:类型:%T 容量:%d 长度:%d \n", bufferChannel, cap(bufferChannel), len(bufferChannel)) // 缓冲通道:类型:chan int 容量:5 长度:0
	bufferChannel <- "bbb"
	fmt.Printf("缓冲通道:类型:%T 容量:%d 长度:%d \n", bufferChannel, cap(bufferChannel), len(bufferChannel)) // 缓冲通道:类型:chan int 容量:5 长度:0
	bufferChannel <- "ccc"
	fmt.Printf("缓冲通道:类型:%T 容量:%d 长度:%d \n", bufferChannel, cap(bufferChannel), len(bufferChannel)) // 缓冲通道:类型:chan int 容量:5 长度:0
	bufferChannel <- "ddd"
	fmt.Printf("缓冲通道:类型:%T 容量:%d 长度:%d \n", bufferChannel, cap(bufferChannel), len(bufferChannel)) // 缓冲通道:类型:chan int 容量:5 长度:0
	bufferChannel <- "eee"
	fmt.Printf("缓冲通道:类型:%T 容量:%d 长度:%d \n", bufferChannel, cap(bufferChannel), len(bufferChannel)) // 缓冲通道:类型:chan int 容量:5 长度:0

	//// 超出缓冲通道的容量。产生死锁 deadlock!
	// bufferChannel <- "fff"
	// fmt.Printf("缓冲通道:类型:%T 容量:%d 长度:%d \n", bufferChannel, cap(bufferChannel), len(bufferChannel)) // 缓冲通道:类型:chan int 容量:5 长度:0
	fmt.Println("****************")
	bufferChan := make(chan string, 4) // 读的量和取存在多元化。写入时间取决于读的时间! 4 表示一次写4个到通道
	go addDataChanFunc(bufferChan)
	for data := range bufferChan {
		time.Sleep(1 * time.Second)
		fmt.Println("main 读取 bufferChan 中的数据:", data)
	}
	fmt.Println("Main end")

}

定向通道

  • 双向通道: 边写边读
  • 单项通道: 只读/只写
package main

import (
	"fmt"
	"sync"
)

func writeOnlyChan(ch chan<- int) {

	// 单向通道:只写操作
	data := 1
	ch <- data
	fmt.Println("只写通道:", data)
	wg.Done()

}
func readOnlyChan(ch <-chan int) int {

	// 单向通道:只写操作
	data := <-ch
	fmt.Println("只读通道:", data)
	wg.Done()
	return data

}

// 定义 同步等待组
var wg sync.WaitGroup

func main() {
	/*
		定向通道:
			- 双向通道: 边写边读
			- 单项通道: 只读/只写
	*/
	// 双向通道:读写
	readWriteChan := make(chan int, 1)
	readWriteChan <- 1
	data := <-readWriteChan
	fmt.Println(data)

	// 单项通道
	//// writeChan := make(chan<- int) // 只写 : 一般用于参数场景。函数参数,防止通道滥用
	//// readChan := make(<-chan int)  // 只读:  一般用于参数场景。函数参数,防止通道滥用

	chan01 := make(chan int)
	wg.Add(2)
	go writeOnlyChan(chan01)
	go readOnlyChan(chan01)
	wg.Wait()

}

Select 和 channel 使用

package main

import (
	"fmt"
	"time"
)

func main() {
	/* 通道中的select */
	ch1 := make(chan int)
	ch2 := make(chan int)
	go func() {
		time.Sleep(1 * time.Second * 2)
		ch1 <- 1
	}()
	go func() {
		time.Sleep(1 * time.Second * 2)
		ch2 <- 109
	}()

	// 读取chan中的数据。无论谁先放入。就使用谁的数据,其他的抛弃
	// select 和 switch 。 只是在通道中使用,case表达式需要一个通道结果
	select {
	case num1 := <-ch1: // 需要一个具体的结果,即从通道中取出来的数据
		fmt.Println("num1:", num1)
	case num2 := <-ch2:
		fmt.Println("num2:", num2)
		//default:
		//	fmt.Println("没拿到通道中的数据!")
	}
}

Timer定时器和 channel 通道

package main

import (
	"fmt"
	"time"
)

func main() {
	/* Timer 定时器 */
	// 创建一个定时器
	//  C <-chan Time 。 只读通道,这个通道中存放的值就是 NewTimer 传入的时间
	timerObj := time.NewTimer(time.Second * 3)

	//当前时间
	fmt.Println(time.Now())
	timeChan := timerObj.C
	fmt.Println(<-timeChan) // 获取 定时器对象中的时间

}

posted @ 2024-07-03 01:14  染指未来  阅读(18)  评论(0编辑  收藏  举报