go語言判斷通道可讀可寫的簡單介紹

golang - channel

通過var聲明或者make函數(shù)創(chuàng)建的channel變量是一個(gè)存儲(chǔ)在函數(shù)棧幀上的指針,占用8個(gè)字節(jié),指向堆上的hchan結(jié)構(gòu)體

昭平網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、成都響應(yīng)式網(wǎng)站建設(shè)等網(wǎng)站項(xiàng)目制作,到程序開發(fā),運(yùn)營維護(hù)。創(chuàng)新互聯(lián)自2013年創(chuàng)立以來到現(xiàn)在10年的時(shí)間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)

源碼包中src/runtime/chan.go定義了hchan的數(shù)據(jù)結(jié)構(gòu)如下:

hchan結(jié)構(gòu)體的主要組成部分有四個(gè):

用來保存goroutine之間傳遞數(shù)據(jù)的循環(huán)數(shù)組:buf

用來記錄此循環(huán)數(shù)組當(dāng)前發(fā)送或接收數(shù)據(jù)的下標(biāo)值:sendx和recvx

用于保存向該chan發(fā)送和從該chan接收數(shù)據(jù)被阻塞的goroutine隊(duì)列: sendq 和 recvq

保證channel寫入和讀取數(shù)據(jù)時(shí)線程安全的鎖:lock

環(huán)形數(shù)組作為channel 的緩沖區(qū) 數(shù)組的長度就是定義channnel 時(shí)channel 的緩沖大小

在hchan 中包括了讀/寫 等待隊(duì)列, waitq是一個(gè)雙向隊(duì)列,包括了一個(gè)頭結(jié)點(diǎn)和尾節(jié)點(diǎn)。 每個(gè)節(jié)點(diǎn)是一個(gè)sudog結(jié)構(gòu)體變量

channel有2種類型:無緩沖、有緩沖, 在創(chuàng)建時(shí) make(chan type cap) 通過cap 設(shè)定緩沖大小

channel有3種模式:寫操作模式(單向通道)、讀操作模式(單向通道)、讀寫操作模式(雙向通道)

channel有3種狀態(tài):未初始化、正常、關(guān)閉

如下幾種狀態(tài)會(huì)引發(fā)panic

channel 是線程安全的,channel的底層實(shí)現(xiàn)中,hchan結(jié)構(gòu)體中采用Mutex鎖來保證數(shù)據(jù)讀寫安全。在對(duì)循環(huán)數(shù)組buf中的數(shù)據(jù)進(jìn)行入隊(duì)和出隊(duì)操作時(shí),必須先獲取互斥鎖,才能操作channel數(shù)據(jù)

golang-文件讀寫

文件分類:文本文件和二進(jìn)制文件

文本文件可讀性好,占用的數(shù)據(jù)空間大

二進(jìn)制文件,可讀性差,占用的數(shù)據(jù)空間小

文件存取方式:隨機(jī)存取和順序存放

隨機(jī)存?。翰僮魉俣嚷?,對(duì)磁盤的消耗大

順序存放:操作數(shù)據(jù)塊,對(duì)磁盤的消耗小

初級(jí)方法

高級(jí)方法

在程序和文件之間,添加一個(gè)緩沖區(qū),每次程序讀取文件內(nèi)容的時(shí)候,先去緩沖區(qū)查看,如果需要的內(nèi)容,直接獲取,如果沒有再去文件中獲取

由于緩沖是在內(nèi)存當(dāng)中的,和程序的交互返回速度會(huì)非???,這樣可以大大提高程序的性能和速度

缺點(diǎn):有的數(shù)據(jù)是只在緩沖中存儲(chǔ)的,如果在緩沖釋放之前,沒有將數(shù)據(jù)實(shí)例化落盤,會(huì)導(dǎo)致數(shù)據(jù)的丟失

按行操作文件對(duì)象

將之前的file方法封裝起來,可以更加方便的使用

使用gzip.NewReader(文件句柄),來操作壓縮文件

示例: file,err := os.OpenFile("main.go", os.O_WRONLY|os.O_WRONLY, 0666)

三個(gè)參數(shù),

文件操作方法,需要注意不能沖突

操作完成后,當(dāng)前目錄出現(xiàn)一個(gè)text.txt 文件,內(nèi)容是:hello world,test

這里可以可以考慮使用buffio來實(shí)現(xiàn)

圖解Go中select語句的底層原理

Go 的select語句是一種僅能用于channl發(fā)送和接收消息的專用語句,此語句運(yùn)行期間是阻塞的;當(dāng)select中沒有case語句的時(shí)候,會(huì)阻塞當(dāng)前的groutine。所以,有人也會(huì)說select是用來阻塞監(jiān)聽goroutine的。

還有人說:select是Golang在語言層面提供的I/O多路復(fù)用的機(jī)制,其專門用來檢測多個(gè)channel是否準(zhǔn)備完畢:可讀或可寫。

以上說法都正確。

我們來回顧一下是什么是 I/O多路復(fù)用 。

每來一個(gè)進(jìn)程,都會(huì)建立連接,然后阻塞,直到接收到數(shù)據(jù)返回響應(yīng)。

普通這種方式的缺點(diǎn)其實(shí)很明顯:系統(tǒng)需要?jiǎng)?chuàng)建和維護(hù)額外的線程或進(jìn)程。因?yàn)榇蠖鄶?shù)時(shí)候,大部分阻塞的線程或進(jìn)程是處于等待狀態(tài),只有少部分會(huì)接收并處理響應(yīng),而其余的都在等待。系統(tǒng)為此還需要多做很多額外的線程或者進(jìn)程的管理工作。

為了解決圖中這些多余的線程或者進(jìn)程,于是有了"I/O多路復(fù)用"

每個(gè)線程或者進(jìn)程都先到圖中”裝置“中注冊,然后阻塞,然后只有一個(gè)線程在”運(yùn)輸“,當(dāng)注冊的線程或者進(jìn)程準(zhǔn)備好數(shù)據(jù)后,”裝置“會(huì)根據(jù)注冊的信息得到相應(yīng)的數(shù)據(jù)。從始至終kernel只會(huì)使用圖中這個(gè)黃黃的線程,無需再對(duì)額外的線程或者進(jìn)程進(jìn)行管理,提升了效率。

select的實(shí)現(xiàn)經(jīng)歷了多個(gè)版本的修改,當(dāng)前版本為:1.11

select這個(gè)語句底層實(shí)現(xiàn)實(shí)際上主要由兩部分組成: case語句 和 執(zhí)行函數(shù) 。

源碼地址為:/go/src/runtime/select.go

每個(gè)case語句,單獨(dú)抽象出以下結(jié)構(gòu)體:

結(jié)構(gòu)體可以用下圖表示:

然后執(zhí)行select語句實(shí)際上就是調(diào)用 func selectgo(cas0 *scase, order0 *uint16, ncases int) (int, bool) 函數(shù)。

func selectgo(cas0 *scase, order0 *uint16, ncases int) (int, bool) 函數(shù)參數(shù):

selectgo 返回所選scase的索引(該索引與其各自的select {recv,send,default}調(diào)用的序號(hào)位置相匹配)。此外,如果選擇的scase是接收操作(recv),則返回是否接收到值。

誰負(fù)責(zé)調(diào)用 func selectgo(cas0 *scase, order0 *uint16, ncases int) (int, bool) 函數(shù)呢?

在 /reflect/value.go 中有個(gè) func rselect([]runtimeSelect) (chosen int, recvOK bool) 函數(shù),此函數(shù)的實(shí)現(xiàn)在 /runtime/select.go 文件中的 func reflect_rselect(cases []runtimeSelect) (int, bool) 函數(shù)中:

那誰調(diào)用的 func rselect([]runtimeSelect) (chosen int, recvOK bool) 呢?

在 /refect/value.go 中,有一個(gè) func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) 的函數(shù),其調(diào)用了 rselect 函數(shù),并將最終Go中select語句的返回值的返回。

以上這三個(gè)函數(shù)的調(diào)用棧按順序如下:

這仨函數(shù)中無論是返回值還是參數(shù)都大同小異,可以簡單粗暴的認(rèn)為:函數(shù)參數(shù)傳入的是case語句,返回值返回被選中的case語句。

那誰調(diào)用了 func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) 呢?

可以簡單的認(rèn)為是系統(tǒng)了。

來個(gè)簡單的圖:

前兩個(gè)函數(shù) Select 和 rselect 都是做了簡單的初始化參數(shù),調(diào)用下一個(gè)函數(shù)的操作。select真正的核心功能,是在最后一個(gè)函數(shù) func selectgo(cas0 *scase, order0 *uint16, ncases int) (int, bool) 中實(shí)現(xiàn)的。

打亂傳入的case結(jié)構(gòu)體順序

鎖住其中的所有的channel

遍歷所有的channel,查看其是否可讀或者可寫

如果其中的channel可讀或者可寫,則解鎖所有channel,并返回對(duì)應(yīng)的channel數(shù)據(jù)

假如沒有channel可讀或者可寫,但是有default語句,則同上:返回default語句對(duì)應(yīng)的scase并解鎖所有的channel。

假如既沒有channel可讀或者可寫,也沒有default語句,則將當(dāng)前運(yùn)行的groutine阻塞,并加入到當(dāng)前所有channel的等待隊(duì)列中去。

然后解鎖所有channel,等待被喚醒。

此時(shí)如果有個(gè)channel可讀或者可寫ready了,則喚醒,并再次加鎖所有channel,

遍歷所有channel找到那個(gè)對(duì)應(yīng)的channel和G,喚醒G,并將沒有成功的G從所有channel的等待隊(duì)列中移除。

如果對(duì)應(yīng)的scase值不為空,則返回需要的值,并解鎖所有channel

如果對(duì)應(yīng)的scase為空,則循環(huán)此過程。

在想想select和channel做了什么事兒,我覺得和多路復(fù)用是一回事兒

Go語言的特點(diǎn)

類型 在變量名后邊

也可不顯式聲明類型, 類型推斷, 但是是靜態(tài)語言, name一開始放字符串就不能再賦值數(shù)字

方法,屬性 分開 方法名首字母大寫就是就是外部可調(diào)的

面向?qū)ο笤O(shè)計(jì)的一個(gè)重要原則:“優(yōu)先使用組合而不是繼承”

Dog 也是Animal , 要復(fù)用Animal 的屬性和方法,

只需要在結(jié)構(gòu)體 type 里面寫 Animal

入口也是main, 用用試試

多態(tài), 有這個(gè)方法就是這個(gè)接口的實(shí)現(xiàn), 具體的類 不需要知道自己實(shí)現(xiàn)了什么接口,

使用: 在一個(gè)函數(shù)調(diào)用之前加上關(guān)鍵字go 就啟動(dòng)了一個(gè)goroutine

創(chuàng)建一個(gè)goroutine,它會(huì)被加入到一個(gè)全局的運(yùn)行隊(duì)列當(dāng)中,

調(diào)度器 會(huì)把他們分配給某個(gè) 邏輯處理器 的隊(duì)列,

一個(gè)邏輯處理器 綁定到一個(gè) 操作系統(tǒng)線程 ,在上面運(yùn)行g(shù)oroutine,

如果goroutine需要讀寫文件, 阻塞 ,就脫離邏輯處理器 直接 goroutine - 系統(tǒng)線程 綁定

編譯成同名.exe 來執(zhí)行, 不通過虛擬機(jī), 直接是機(jī)器碼, 和C 一樣, 所以非常快

但是也有自動(dòng)垃圾回收,每個(gè)exe文件當(dāng)中已經(jīng)包含了一個(gè)類似于虛擬機(jī)的runtime,進(jìn)行g(shù)oroutine的調(diào)度

默認(rèn)是靜態(tài)鏈接的,那個(gè)exe會(huì)把運(yùn)行時(shí)所需要的所有東西都加進(jìn)去,這樣就可以把exe復(fù)制到任何地方去運(yùn)行了, 因此 生成的 .exe 文件非常大

go語言語法(基礎(chǔ)語法篇)

import "workname/packetfolder"

導(dǎo)入多個(gè)包

方法調(diào)用 包名.函數(shù)//不是函數(shù)或結(jié)構(gòu)體所處文件或文件夾名

packagename.Func()

前面加個(gè)點(diǎn)表示省略調(diào)用,那么調(diào)用該模塊里面的函數(shù),可以不用寫模塊名稱了:

當(dāng)導(dǎo)入一個(gè)包時(shí),該包下的文件里所有init()函數(shù)都會(huì)被執(zhí)行,然而,有些時(shí)候我們并不需要把整個(gè)包都導(dǎo)入進(jìn)來,僅僅是是希望它執(zhí)行init()函數(shù)而已。下劃線的作用僅僅是為了調(diào)用init()函數(shù),所以無法通過包名來調(diào)用包中的其他函數(shù)

import _ package

變量聲明必須要使用否則會(huì)報(bào)錯(cuò)。

全局變量運(yùn)行聲明但不使用。

func 函數(shù)名 (參數(shù)1,參數(shù)2,...) (返回值a 類型a, 返回值b 類型b,...)

func 函數(shù)名 (參數(shù)1,參數(shù)2,...) (返回值類型1, 返回值類型2,...)

func (this *結(jié)構(gòu)體名) 函數(shù)名(參數(shù) string) (返回值類型1, 返回值類型2){}

使用大小來區(qū)分函數(shù)可見性

大寫是public類型

小寫是private類型

func prifunc int{}

func pubfunc int{}

聲明靜態(tài)變量

const value int

定義變量

var value int

聲明一般類型、接口和結(jié)構(gòu)體

聲明函數(shù)

func function () int{}

go里面所有的空值對(duì)應(yīng)如下

通道類型

內(nèi)建函數(shù) new 用來分配內(nèi)存,它的第一個(gè)參數(shù)是一個(gè)類型,不是一個(gè)值,它的返回值是一個(gè)指向新分配類型零值的指針

func new(Type) *Type

[這位博主有非常詳細(xì)的分析]

Go 語言支持并發(fā),我們只需要通過 go 關(guān)鍵字來開啟 goroutine 即可。

goroutine 是輕量級(jí)線程,goroutine 的調(diào)度是由 Golang 運(yùn)行時(shí)進(jìn)行管理的。

同一個(gè)程序中的所有 goroutine 共享同一個(gè)地址空間。

語法格式如下:

通道(channel)是用來傳遞數(shù)據(jù)的一個(gè)數(shù)據(jù)結(jié)構(gòu)。

通道的聲明

通道可用于兩個(gè) goroutine 之間通過傳遞一個(gè)指定類型的值來同步運(yùn)行和通訊。操作符 - 用于指定通道的方向,發(fā)送或接收。如果未指定方向,則為雙向通道。

[這里有比較詳細(xì)的用例]

go里面的空接口可以指代任何類型(無論是變量還是函數(shù))

聲明空接口

go里面的的強(qiáng)制類型轉(zhuǎn)換語法為:

int(data)

如果是接口類型的強(qiáng)制轉(zhuǎn)成其他類型的語法為:

go里面的強(qiáng)制轉(zhuǎn)換是將值復(fù)制過去,所以在數(shù)據(jù)量的時(shí)候有比較高的運(yùn)行代價(jià)

每天一個(gè)知識(shí)點(diǎn):Go?語言當(dāng)中?Channel(通道)有什么特點(diǎn),需要注意什么?

使用簡單的 make 調(diào)用創(chuàng)建的通道叫做無緩沖通道,但 make 還可以接受第二個(gè)可選參數(shù),一個(gè)表示通道容量的整數(shù)。如果容量是 0,make 創(chuàng)建一個(gè)無緩沖通道。

無緩沖通道上的發(fā)送操作將被阻塞,直到另一個(gè) goroutine 在對(duì)應(yīng)的通道上執(zhí)行接受操作,這時(shí)值傳送完成,兩個(gè) goroutine 都可以繼續(xù)執(zhí)行。相反,如果接受操作先執(zhí)行,接收方 goroutine 將阻塞,直到另一個(gè) goroutine 在同一個(gè)通道上發(fā)送一個(gè)值。使用無緩沖通道進(jìn)行的通信導(dǎo)致發(fā)送和接受操作 goroutine 同步化。因此,無緩沖通道也稱為同步通道。當(dāng)一個(gè)值在無緩沖通道上傳遞時(shí),接受值后發(fā)送方 goroutine 才能被喚醒。

緩沖通道上的發(fā)送操作在隊(duì)列的尾部插入一個(gè)元素,接收操作從隊(duì)列的頭部移除一個(gè)元素。如果通道滿了,發(fā)送操作會(huì)阻塞所在的 goroutine 直到另一個(gè) goroutine 對(duì)它進(jìn)行接收操作來留出可用的空間。反過來,如果通道是空的,執(zhí)行接收操作的 goroutine 阻塞,直到另一個(gè) goroutine 在通道上發(fā)送數(shù)據(jù)。

如果給一個(gè) nil 的 channel 發(fā)送數(shù)據(jù),會(huì)造成永遠(yuǎn)阻塞。

如果從一個(gè) nil 的 channel 中接收數(shù)據(jù),也會(huì)造成永久阻塞。 給一個(gè)已經(jīng)關(guān)閉的 channel 發(fā)送數(shù)據(jù), 會(huì)引起 panic。

從一個(gè)已經(jīng)關(guān)閉的 channel 接收數(shù)據(jù), 如果緩沖區(qū)中為空,則返回一個(gè) 零 值。

分享文章:go語言判斷通道可讀可寫的簡單介紹
標(biāo)題路徑:http://muchs.cn/article44/doccjhe.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供虛擬主機(jī)、手機(jī)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì)公司響應(yīng)式網(wǎng)站、企業(yè)建站軟件開發(fā)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設(shè)