最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

Go語言goroutine、channel【重點】

2022-10-25 19:08 作者:苦茶今天斷更了嗎  | 我要投稿

Go語言goroutine、channel

進(jìn)程、線程:

進(jìn)程就是程序程序在操作系統(tǒng)中的一次執(zhí)行過程,是系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位。

線程是進(jìn)程的一個執(zhí)行實例,是程序執(zhí)行的最小單元,它是比進(jìn)程更小的能獨立運行的基本單位。

③一個進(jìn)程可以創(chuàng)建和銷毀多個線程,同一個進(jìn)程中的多個線程可以并發(fā)執(zhí)行。

④一個程序至少有一個進(jìn)程,一個進(jìn)程至少有一個線程。

?

并發(fā)多線程程序在單核上運行

因為是在一個cpu上,比如有10個線程,每個線程執(zhí)行10毫秒(進(jìn)行輪詢操作),從人的角度看,好像這10個線程都在運行,但是從微觀上看,在某一個時間點看,其實只有一個線程在執(zhí)行。

?

并行多線程程序在多核上運行

因為是在多個cpu上(比如有10個cpu),比如有10個線程,每個線程執(zhí)行10毫秒(各自在不同cpu上執(zhí)行),從人的角度看,這10個線程都在運行,但是從微觀上看,在某一個時間點看,也同時有10個線程在執(zhí)行。

Go協(xié)程goroutine、Go主線程:

Go主線程(有程序員直接稱為線程?/?也可以理解成進(jìn)程):一個Go線程上,可以起多個協(xié)程goroutine,可以這樣理解,協(xié)程是輕量級的線程【編譯器做優(yōu)化】。

Go協(xié)程goroutine的特點:

①有獨立的??臻g

②共享程序堆空間

③調(diào)度由用戶控制

④協(xié)程是輕量級的線程

Go協(xié)程goroutine的案例:

1.在主線程(可以理解成進(jìn)程)中,開啟一個goroutine,該協(xié)程每隔1秒輸出"hello,world"。

2.在主線程中也每隔一秒輸出"hello.golang",輸出10次后,退出程序。

3.要求主線程和goroutine同時執(zhí)行。

①如果主線程退出了,協(xié)程沒執(zhí)行完畢也會退出。

②主線程是一個物理線程,直接作用在cpu上的。是重量級的,非常耗費cpu資源。

③協(xié)程從主線程開啟的,是輕量級的線程,是邏輯態(tài)。對資源消耗相對小。

④Golang的協(xié)程機制是重要的特點,可以輕松的開啟上萬個協(xié)程。其它編程語言的并發(fā)機制是一般基于線程的,開啟過多的線程,資源耗費大,這里就突顯Golang 在并發(fā)上的優(yōu)勢了。

?

Go協(xié)程goroutine的調(diào)度模型:

MPG:

M:操作系統(tǒng)的主線程(是物理線程)

P:協(xié)程執(zhí)行需要的上下文

G:協(xié)程

MPG模式運行的狀態(tài)1:

當(dāng)前程序有三個M,如果都在一個cpu運行,就是并發(fā),如果在不同的cpu運行,就是并行。

?

MPG模式運行的狀態(tài)2:

分成兩個部分來看;

M0主線程正在執(zhí)行G0協(xié)程,另外有三個協(xié)程在隊列等待。

如果G0協(xié)程阻塞,這時就會創(chuàng)建M1主線程(也可能是從已有的線程池中取出M1),并且將等待的3個協(xié)程掛到M1下開始執(zhí)行,M0的主線程下的G0仍然執(zhí)行。

這樣的MPG調(diào)度模式,可以既讓G0執(zhí)行,同時也不會讓隊列的其它協(xié)程一直阻塞,仍然可以并發(fā)/并行執(zhí)行。

等到G0不阻塞了,M0會被放到空閑的主線程繼續(xù)執(zhí)行(從已有的線程池中?。瑫rG0又會被喚醒。

?

設(shè)置Golang運行的cpu數(shù):

為了充分利用多cpu的優(yōu)勢,在Golang程序中,設(shè)置運行的cpu數(shù)目。

go1.8后,默認(rèn)讓程序運行在多個核上,可以不用設(shè)置了。

go1.8前,還是要設(shè)置一下,可以更高效的利益cpu。

?

channel(管道)-看個需求

需求:

現(xiàn)在要計算 1-200 的各個數(shù)的階乘,并且把各個數(shù)的階乘放入到map中。

最后顯示出來。要求使用goroutine完成

思路:

1. 編寫一個函數(shù),來計算各個數(shù)的階乘,并放入到 map中。

2. 我們啟動的協(xié)程多個,統(tǒng)計的將結(jié)果放入到 map中。

3. map 應(yīng)該做出一個全局的。

4.因為沒有對全局變量m加鎖,因此會出現(xiàn)資源爭奪問題,代碼會出現(xiàn)錯誤,提示 concurrent map?writes。解決方案:加入互斥鎖。

?

不同goroutine之間如何通訊

①全局變量的互斥鎖

②使用管道channel來解決

?


為什么需要channel

①前面使用全局變量加鎖同步來解決goroutine的通訊,但不完美

②主線程在等待所有 goroutine全部完成的時間很難確定,這里設(shè)置10秒,僅僅是估算。

③如果主線程休眠時間長了,會加長等待時間,如果等待時間短了,可能還有 goroutine 處于工作狀態(tài),這時也會隨主線程的退出而銷毀

通過全局變量加鎖同步來實現(xiàn)通訊,也并不利于多個協(xié)程對全局變量的讀寫操作。

⑤上面種種分析都在呼喚一個新的通訊機制-channe1

?

channel的基本介紹

Go語言中的通道(channel)是一種特殊的類型。

在任何時候,同時只能有一個goroutine訪問通道進(jìn)行發(fā)送和獲取數(shù)據(jù)。

①channel本身是一個隊列,先進(jìn)先出

②線程安全,多goroutine訪問時,不需要加鎖

③本身是有類型的,string,int等,如果要存多種類型,則定義成interface類型

channel是引用類型,必須make后才能使用,一旦make,容量就確定了,不會增加!!

?


特點:

①一旦初始化容量,就不會改變了。

②當(dāng)寫滿時,不可以寫,取空時,不可以取,否則報dead lock。

③發(fā)送將持續(xù)阻塞直到數(shù)據(jù)被接收。

Go程序運行時能智能地發(fā)現(xiàn)一些永遠(yuǎn)無法發(fā)送成功的語句并做出提示。

④接收將持續(xù)阻塞直到發(fā)送方發(fā)送數(shù)據(jù)。

如果接收方接收時,通道中沒有發(fā)送方發(fā)送數(shù)據(jù),接收方也會發(fā)生阻塞,直到發(fā)送方發(fā)送數(shù)據(jù)為止。

⑤通道一次只能接收一個數(shù)據(jù)元素。

?

定義/聲明channel:var變量名chan數(shù)據(jù)類型

舉例:

Var intChan chan int (intChan用于存放int數(shù)據(jù))

Var mapChan chan map[int]string (mapChan用于存放map[int]string類型)

Var perChan chan Person

Var perChan2 chan *Person

說明:

channel是引用類型;

channel必須初始化才能寫入數(shù)據(jù),即make后才能使用管道是有類型的。

?

管道的初始化,寫入數(shù)據(jù)到管道,從管道讀取數(shù)據(jù)

fmt.Printf("intChan的值=%v ?intChan本身的地址=%p\n", ?intChan, ?&intChan):

channel和指針一樣,存放在一個內(nèi)存單元中,有它的地址,它的值是一個int類型的地址。

?

讀寫channel案例演示:

①創(chuàng)建一個intChan,最多可以存放3個int,存數(shù)據(jù)到intChan,然后再取出這三個int。

②創(chuàng)建一個mapChan,最多可以存放10個map[string]string的key-val,演示寫入和讀取。

③創(chuàng)建一個catChan,最多可以存放10個cat結(jié)構(gòu)體變量,演示寫入和讀取。

?④創(chuàng)建一個catChan2,最多可以存放10個*Cat變量,演示寫入和讀取

?⑤創(chuàng)建一個allChan,最多可以存放10個任意數(shù)據(jù)類型變量,演示寫入和讀取

?⑥注意空接口類型的 channel:


定義interface類型的空接口,可以接收任意類型的數(shù)據(jù),但是在取出來的時候,必須斷言!a := newCat.(Cat)

?

channel的關(guān)閉:close( )

關(guān)閉之后,不能再寫入,只能讀。只能由發(fā)送者執(zhí)行這句代碼。

?

channel 的遍歷for--range遍歷,不用for循環(huán)

①在遍歷時,如果channel沒有關(guān)閉,則出現(xiàn)deadlock的錯誤

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

應(yīng)用

實例1:請完成goroutine和channel協(xié)同工作的案例,具體要求:

①開啟一個writeData協(xié)程,向管道intChan中寫入50個整數(shù);

②開啟一個readData協(xié)程,從管道intChan中讀取writeData寫入的數(shù)據(jù);

③注意: writeData和readDate操作的是同一個管道;

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

方法:

①開兩個管道;

②當(dāng)writeData協(xié)程完成后,close數(shù)據(jù)管道,readData協(xié)程對數(shù)據(jù)管道intChan的數(shù)據(jù)讀完之后,就向退出管道exitChan寫入一個 true,close掉;

③主線程循環(huán)檢測退出管道里是否有數(shù)據(jù),如果有,說明readData協(xié)程完成,主程序就可以退出了。

實例2:要求統(tǒng)計1-200000的數(shù)字中,哪些是素數(shù)?

分析思路:使用并發(fā)/并行的方式,將統(tǒng)計素數(shù)的任務(wù)分配給多個(4個)goroutine去完成。

定義三個管道:

intChan :放80000個數(shù)

primeChan:放素數(shù)

exitChan :4個協(xié)程運行完畢的標(biāo)志

?

?

?channel使用細(xì)節(jié)和注意事項

①channel可以聲明為只讀?/ 只寫性質(zhì)

使select可以解決從管道取數(shù)據(jù)的阻塞問題不知道何時關(guān)閉管道時

③goroutine中使用recover,解決“協(xié)程中出現(xiàn)panic,導(dǎo)致程序崩潰”的問題。

?

?通道的數(shù)據(jù)接收,?4種寫法。

阻塞接收數(shù)據(jù)

將接收變量作為<-操作符的左值,格式:data := <-ch

執(zhí)行該語句時將會阻塞,直到接收到數(shù)據(jù)并賦值給data變量。

?

②非阻塞接收數(shù)據(jù)

語句不會發(fā)生阻塞,格式:data, ok := <-ch

data:表示接收到的數(shù)據(jù)。未接收到數(shù)據(jù)時,data為通道類型的零值。

ok:表示是否接收到數(shù)據(jù)。

非阻塞的通道接收方法可能造成高的CPU占用,因此使用非常少。如果需要實現(xiàn)接收超時檢測,可以配合 select 和計時器 channel進(jìn)行。

?

③接收任意數(shù)據(jù),忽略接收的數(shù)據(jù)

阻塞接收數(shù)據(jù)后,忽略從通道返回的數(shù)據(jù),格式:<-ch

執(zhí)行該語句時將會發(fā)生阻塞,直到接收到數(shù)據(jù),但接收到的數(shù)據(jù)會被忽略。

這個方式實際上只是通過通道在 goroutine 間阻塞收發(fā)實現(xiàn)并發(fā)同步。

?

使用通道做并發(fā)同步的寫法,可以參考下面的例子:


④循環(huán)接收

通道的數(shù)據(jù)接收可以借用for range語句進(jìn)行多個元素的接收操作,格式:

for data := range ch {

}

通道ch是可以進(jìn)行遍歷的,遍歷的結(jié)果就是接收到的數(shù)據(jù)。數(shù)據(jù)類型就是通道的數(shù)據(jù)類型。通過for遍歷獲得的變量只有一個,即上面例子中的data。

?

?


Go語言goroutine、channel【重點】的評論 (共 條)

分享到微博請遵守國家法律
津南区| 托克托县| 平顶山市| 兴和县| 三亚市| 晴隆县| 上林县| 潜山县| 阳城县| 永德县| 安陆市| 兴隆县| 信阳市| 石屏县| 青铜峡市| 安阳县| 鹤庆县| 桐梓县| 灵丘县| 耒阳市| 彝良县| 杂多县| 洛川县| 突泉县| 鄯善县| 黄石市| 呼伦贝尔市| 林州市| 德钦县| 奉化市| 乌审旗| 女性| 益阳市| 抚顺市| 壤塘县| 呼玛县| 炉霍县| 武邑县| 大余县| 仁怀市| 北海市|