自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

聊聊協(xié)程和管道—管道

開(kāi)發(fā) 前端
使用內(nèi)置函數(shù)close可以關(guān)閉管道,當(dāng)管道關(guān)閉后,就不能再向管道寫(xiě)數(shù)據(jù)了,但是仍然可以從該管道讀取數(shù)據(jù)。

管道簡(jiǎn)介

【1】管道(channel)特質(zhì)介紹:

(1)管道本質(zhì)就是一個(gè)數(shù)據(jù)結(jié)構(gòu)-隊(duì)列

(2)數(shù)據(jù)是先進(jìn)先出

(3)自身線程安全,多協(xié)程訪問(wèn)時(shí),不需要加鎖,channel本身就是線程安全的

(4)管道有類型的,一個(gè)string的管道只能存放string類型數(shù)據(jù)

管道入門案例

【1】管道的定義:

var 變量名 chan 數(shù)據(jù)類型

PS1:chan管道關(guān)鍵字

PS2:數(shù)據(jù)類型指的是管道的類型,里面放入數(shù)據(jù)的類型,管道是有類型的,int類型的管道只能寫(xiě)入整數(shù)int

PS3:管道是引用類型,必須初始化才能寫(xiě)入數(shù)據(jù),即make后才能使用

【2】案例:

func main()  {
	//定義管道 、 聲明管道 ---> 定義一個(gè)int類型的管道
	var intChan chan int
	//通過(guò)make初始化:管道可以存放3個(gè)int類型的數(shù)據(jù)
	intChan = make(chan int, 3)

	//證明管道是引用類型:
	fmt.Printf("intChan的值: %v \n",intChan)

	//向管道存放數(shù)據(jù):
	intChan <- -10
	num := 20
	intChan <- num
	intChan <- 40
	//注意:不能存放大于容量的數(shù)據(jù):
	// intChan <- -80
	//輸出管道的長(zhǎng)度:
	fmt.Printf("管道的實(shí)際長(zhǎng)度:%v,管道的容量是:%v \n",len(intChan),cap(intChan))

	//在管道中讀取數(shù)據(jù):
	num1 := <-intChan
	num2 := <-intChan
	num3 := <-intChan
	fmt.Println(num1)
	fmt.Println(num2)
	fmt.Println(num3)

	//注意:在沒(méi)有使用協(xié)程的情況下,如果管道的數(shù)據(jù)已經(jīng)全部取出,那么再取就會(huì)報(bào)錯(cuò):
	// num4 := <-intChan
	// fmt.Println(num4)

	fmt.Printf("管道的實(shí)際長(zhǎng)度:%v,管道的容量是:%v \n",len(intChan),cap(intChan))
}

管道的關(guān)閉

【1】管道的關(guān)閉:

使用內(nèi)置函數(shù)close可以關(guān)閉管道,當(dāng)管道關(guān)閉后,就不能再向管道寫(xiě)數(shù)據(jù)了,但是仍然可以從該管道讀取數(shù)據(jù)。

【2】案例:

func main()  {
	var intChan chan int
	intChan = make(chan int, 3)
	intChan <- 10
	intChan <- 20
	//關(guān)閉管道:
	close(intChan)
	//再次寫(xiě)入數(shù)據(jù):--->報(bào)錯(cuò)
	// intChan <- 30
	//當(dāng)管道關(guān)閉后,讀取數(shù)據(jù)是可以的:
	num := <- intChan
	fmt.Println(num)
}

管道的遍歷

【1】管道的遍歷:

管道支持for-range的方式進(jìn)行遍歷,請(qǐng)注意兩個(gè)細(xì)節(jié)

1)在遍歷時(shí),如果管道沒(méi)有關(guān)閉,則會(huì)出現(xiàn)deadlock的錯(cuò)誤

2)在遍歷時(shí),如果管道已經(jīng)關(guān)閉,則會(huì)正常遍歷數(shù)據(jù),遍歷完后,就會(huì)退出遍歷。

【2】案例:

func main()  {
	var intChan chan int
	intChan = make(chan int, 100)
	for i := 0; i < 100; i++ {
		intChan <- i
	}

	//在遍歷前,如果沒(méi)有關(guān)閉管道,就會(huì)出現(xiàn)deadlock的錯(cuò)誤
	//所以我們?cè)诒闅v前要進(jìn)行管道的關(guān)閉
	// for v := range intChan {
	// 	fmt.Println("value = ",v)
	// }
	close(intChan)
	//遍歷:for-range
	for v := range intChan {
		fmt.Println("value = ",v)
	}
}

協(xié)程和管道協(xié)同工作案例

【1】案例需求:

請(qǐng)完成協(xié)程和管道協(xié)同工作的案例,具體要求:

1) 開(kāi)啟一個(gè)writeData協(xié)程,向管道中寫(xiě)入50個(gè)整數(shù).

2) 開(kāi)啟一個(gè)readData協(xié)程,從管道中讀取writeData寫(xiě)入的數(shù)據(jù)。

3) 注意: writeData和readDate操作的是同一個(gè)管道

4) 主線程需要等待writeData和readDate協(xié)程都完成工作才能退出

【2】原理圖:

package main

import (
	"fmt"
	"time"
	"sync"
)

var wg sync.WaitGroup

//寫(xiě):
func writeData(intChan chan int)  {
	defer wg.Done()
	for i := 1; i <= 50; i++ {
		intChan <- i
		fmt.Println("寫(xiě)入的數(shù)據(jù)為:",i)
		time.Sleep(time.Second)
	}	
	close(intChan)
}

//讀:
func readData(intChan chan int) {
	defer wg.Done()
	for v := range intChan {
		fmt.Println("讀取的數(shù)據(jù)為:",v)
		time.Sleep(time.Second)
	}
}

func main()  {
	//主線程
	//寫(xiě)協(xié)程和讀協(xié)程共同操作同一個(gè)管道-》定義管道:
	intChan := make(chan int, 50)
	wg.Add(2)
	//開(kāi)啟讀和寫(xiě)的協(xié)程:
	go writeData(intChan)
	go readData(intChan)
	//主線程一直在阻塞,什么時(shí)候wg減為0了,就停止
	wg.Wait()
	fmt.Println("讀寫(xiě)數(shù)據(jù)完成...")
}

運(yùn)行結(jié)果:

聲明只讀只寫(xiě)管道

【1】管道可以聲明為只讀或者只寫(xiě)性質(zhì)

【2】代碼:

package main

import (
	"fmt"
)

func main()  {
	//默認(rèn)情況下,管道是雙向的--》可讀可寫(xiě):
	//聲明為只寫(xiě):
	// 管道具備<- 只寫(xiě)性質(zhì)
	var intChan chan<- int
	intChan = make(chan int, 3)
	intChan <- 10
	// 報(bào)錯(cuò)
	// num := <- intChan
	fmt.Println("intChan:",intChan)

	//聲明為只讀:
	// 管道具備<- 只讀性質(zhì) 
	var intChan2 <-chan int
	if intChan2 != nil {
		num1 := <- intChan2
		fmt.Println("num1:",num1)
	}
	// 報(bào)錯(cuò)
	// intChan2 <- 30
}

管道的阻塞

【1】當(dāng)管道只寫(xiě)入數(shù)據(jù),沒(méi)有讀取,就會(huì)出現(xiàn)阻塞:

package main

import (
	"fmt"
	"sync"
)

var wg sync.WaitGroup

func writeData(intChan chan int)  {
	defer wg.Done()
	for i := 1; i < 10; i++ {
		intChan <- i
		fmt.Println("寫(xiě)入的數(shù)據(jù):",i)
	}
	close(intChan)
}

func readData(intChan chan int)  {
	defer wg.Done()
	for v := range intChan {
		fmt.Println("讀取的數(shù)據(jù)為:",v)
	}
}

func main()  {
	intChan := make(chan int, 10)

	wg.Add(2)
	go writeData(intChan)
	// go readData(intChan)
	wg.Wait()
}

運(yùn)行結(jié)果

【2】寫(xiě)的快,讀的慢(管道讀寫(xiě)頻率不一致),不會(huì)出現(xiàn)阻塞問(wèn)題:

package main

import (
	"fmt"
	"sync"
	"time"
)

var wg sync.WaitGroup

func writeData(intChan chan int)  {
	defer wg.Done()
	for i := 1; i < 10; i++ {
		intChan <- i
		fmt.Println("寫(xiě)入的數(shù)據(jù):",i)
	}
	close(intChan)
}

func readData(intChan chan int)  {
	defer wg.Done()
	for v := range intChan {
		fmt.Println("讀取的數(shù)據(jù)為:",v)
		time.Sleep(time.Second)
	}
}

func main()  {
	intChan := make(chan int, 10)

	wg.Add(2)
	go writeData(intChan)
	go readData(intChan)
	wg.Wait()
}

select功能

【1】select功能:解決多個(gè)管道的選擇問(wèn)題,也可以叫做多路復(fù)用,可以從多個(gè)管道中隨機(jī)公平地選擇一個(gè)來(lái)執(zhí)行

PS:case后面必須進(jìn)行的是io操作,不能是等值,隨機(jī)去選擇一個(gè)io操作

PS:default防止select被阻塞住,加入default

【2】代碼:

package main

import (
	"fmt"
	"time"
)

func main()  {
	intChan := make(chan int, 1)
	go func ()  {
		time.Sleep(time.Second * 15)
		intChan <- 15
	}()
	stringChan := make(chan string, 1)
	go func ()  {
		time.Sleep(time.Second * 12)
		stringChan <- "hellocyz"
	}()

	//本身取數(shù)據(jù)就是阻塞的
	// fmt.Println(<-intChan)

	select {
		case v := <-intChan : fmt.Println("intChan:",v)
		case v := <-stringChan : fmt.Println("stringChan:",v)
		default: fmt.Println("防止select被阻塞")
	}
}

defer+recover機(jī)制處理錯(cuò)誤

【1】問(wèn)題原因:多個(gè)協(xié)程工作,其中一個(gè)協(xié)程出現(xiàn)panic,導(dǎo)致程序崩潰

【2】解決辦法:利用defer+recover捕獲panic進(jìn)行處理,即使協(xié)程出現(xiàn)問(wèn)題,主線程仍然不受影響可以繼續(xù)執(zhí)行。

【3】案例:

package main

import (
	"fmt"
	"time"
)

//輸出數(shù)字:
func printNum()  {
	for i := 1; i <= 10; i++ {
		fmt.Println(i)	
	}
}

//做除法操作:
func divide()  {
	defer func ()  {
		err := recover()
		if err != nil {
			fmt.Println("devide()出現(xiàn)錯(cuò)誤:",err)
		}
	}()
	num1 := 10
	num2 := 0
	result := num1 / num2
	fmt.Println(result)
}

func main()  {
	//啟動(dòng)兩個(gè)協(xié)程:
	go printNum()
	go divide()
	time.Sleep(time.Second * 5)
}

結(jié)果:

責(zé)任編輯:武曉燕 來(lái)源: 今日頭條
相關(guān)推薦

2022-11-21 06:55:08

golang協(xié)程

2021-02-20 20:36:56

Linux無(wú)名管道

2018-09-10 08:45:04

Linux管道命令

2023-11-29 07:10:50

python協(xié)程異步編程

2021-09-16 09:59:13

PythonJavaScript代碼

2021-04-25 09:36:20

Go協(xié)程線程

2014-04-25 10:13:00

Go語(yǔ)言并發(fā)模式

2020-02-19 14:16:23

kotlin協(xié)程代碼

2014-07-02 21:20:56

CA TechnoloAPI

2020-04-17 08:34:39

Linux管道

2022-11-14 15:07:09

Linux管道

2023-11-17 11:36:59

協(xié)程纖程操作系統(tǒng)

2010-10-25 16:52:48

oracle管道函數(shù)

2021-08-04 16:19:55

AndroidKotin協(xié)程Coroutines

2023-10-24 19:37:34

協(xié)程Java

2009-07-21 14:16:02

ASP.NET管道優(yōu)化

2009-08-19 16:36:29

C#管道技術(shù)

2021-12-31 13:25:44

PythonPipe代碼

2023-05-04 16:03:50

KubernetesCI/CD集成

2020-12-09 11:10:12

shellLinux管道
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)