進(jìn)程和線程
公司主營(yíng)業(yè)務(wù):成都做網(wǎng)站、網(wǎng)站設(shè)計(jì)、移動(dòng)網(wǎng)站開(kāi)發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。成都創(chuàng)新互聯(lián)是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開(kāi)放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來(lái)的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來(lái)驚喜。成都創(chuàng)新互聯(lián)推出陵川免費(fèi)做網(wǎng)站回饋大家。
1. 進(jìn)程是程序在操作系統(tǒng)中的?次執(zhí)?過(guò)程,系統(tǒng)進(jìn)口資源分配和調(diào)度的一個(gè)獨(dú)力單位。
2. 線程是進(jìn)程的一個(gè)執(zhí)行實(shí)體,是CPU調(diào)度和分派的基本單位,它是?進(jìn)程更?的能獨(dú)力運(yùn)行的基本單位。
3. 一個(gè)進(jìn)程可以創(chuàng)建和撤銷(xiāo)多個(gè)線程;同一個(gè)進(jìn)程中的多個(gè)線程之間可以并發(fā)執(zhí)行
Goroutine
并發(fā)和并行
多線程程序在一個(gè)核的CPU上運(yùn)行,就是并發(fā)
多線程程序在多個(gè)核的CPU上運(yùn)行,就是并發(fā)
設(shè)置GO運(yùn)行的CPU核數(shù)
func Test1() { num := runtime.NumCPU() //設(shè)置程序運(yùn)行占幾個(gè)核 runtime.GOMAXPROCS(num) fmt.Println(num) }
線程同步
sync.WaitGroup
package main import ( "fmt" "time" "sync" ) var wailtGroup sync.WaitGroup //sync 線程同步 func Test2(index int) { for i:=0;i<100;i++{ time.Sleep(time.Millisecond) } wailtGroup.Done() } func calc() { start :=time.Now().UnixNano() //Test2(0) for i:=0; i<3;i++{ go Test2(i) wailtGroup.Add(1) } #當(dāng)wailtGroup 為0時(shí),就會(huì)返回 wailtGroup.Wait() end := time.Now().UnixNano() fmt.Printf("finished,cost:%d ms \n",(end - start) / 1000 / 1000) } func main() { //Test1() calc() }
不同goroutine之間通信
全局變量和鎖同步
Channel
Channel
類(lèi)似unix中的管道(pipe)
先進(jìn)先出
線程安全,多個(gè)goroutine同時(shí)訪問(wèn),不需要加鎖
Channel是有類(lèi)型的,一個(gè)整數(shù)的channel只能存放整數(shù)
Channel聲明:
var 變量名 chan 類(lèi)型
var test chan int
var test chan string
var test chan map[string]string
var test chan stu
var test chan *stu
Channel初始化:
不帶緩沖區(qū):默認(rèn)就是0,必須有取值,才可以放入,不然就會(huì)阻塞!
帶緩沖區(qū): 值>0
使用make進(jìn)行初始化
var test chan int
test =make(chan int,10)
var test2 chan string
test = make(chan string,10)
Channel基本操作:
1.從channel讀取數(shù)據(jù)
testChan :=make(chan int,10) var a int a = <- testChan
2.從channel寫(xiě)數(shù)據(jù)
testChan:=make(chan int,10) var a int= 10 testChan <- a
栗子:
1.初級(jí)操作
func test() { var intChan chan int = make(chan int,3) go func(){ fmt.Println("begin input to chan\n") intChan <- 20 intChan <- 20 intChan <- 20 fmt.Println("end input to chan\n") }() result := <- intChan fmt.Printf("--result:%d",result) time.Sleep(2*time.Second) } func main() { test() }
2.goroutine和channel結(jié)合
package main import ( "fmt" "time" ) func main() { ch := make(chan string) go sendData(ch) go getData(ch) //加time原因是讓2個(gè)go去執(zhí)行, 因?yàn)橹骶€程中的代碼是比goroutine先執(zhí)行完畢的 time.Sleep(100 * time.Second) } func sendData(ch chan string) { ch <- "Washington" ch <- "Tripoli" ch <- "London" ch <- "Beijing" ch <- "Tokio" } func getData(ch chan string) { var input string for { input = <-ch fmt.Println(input) } }
for循環(huán)去遍歷chan
package main import ( "fmt" "time" ) func main() { ch := make(chan string) go sendData(ch) go getData(ch) time.Sleep(100 * time.Second) } func sendData(ch chan string) { ch <- "Washington" ch <- "Tripoli" ch <- "London" ch <- "Beijing" ch <- "Tokio" } func getData(ch chan string) { for input := range ch { fmt.Println(input) } }
Channel關(guān)閉
使用內(nèi)置函數(shù)close進(jìn)行關(guān)閉,chan關(guān)閉后。for range遍歷chan中已經(jīng)存在的元素后結(jié)束
func rangegetData(ch chan string) { //另外用法,用來(lái)取管道中的數(shù)據(jù) // for input:=range ch{ fmt.Printf("#%v\n",input) } }
使用內(nèi)置函數(shù)close進(jìn)行關(guān)閉,chan關(guān)閉后。沒(méi)有使用for range的寫(xiě)法需要使用,v,ok := <-ch 進(jìn)行判斷chan是否關(guān)閉
func getData(ch chan string) { //死循環(huán) for { input,ok :=<- ch //ok是判斷管道是否關(guān)閉 if !ok{ fmt.Printf("管道關(guān)閉") break } fmt.Printf("channe_read:%s\n",input) } }
進(jìn)階栗子:
func consumer(ch <-chan string){ for{ str,ok := <- ch if !ok{ fmt.Printf("ch is closed!!") break } fmt.Printf("value is %s \n",str) } } func main(){ var ch chan string = make(chan string) consumer(ch)}
Channel只讀/只寫(xiě)
只讀chan聲明
var 變量名字 <-chan int var readChan <-chan int
只寫(xiě)chan聲明
var 變量名字 chan<-int var writeChan chan<-int
Channel Select管理
注意:調(diào)度是隨機(jī)的
一個(gè)簡(jiǎn)單的栗子:
for { str := fmt.Sprintf("hello %d",i) //select來(lái)管理管道 //調(diào)度是隨機(jī)的, select { case ch <- str: case exit = <-exitChan: } if exit{ fmt.Printf("user notify exitedd!!\n") break } }
定時(shí)器
規(guī)定時(shí)間后運(yùn)行代碼
package main import ( "time" "fmt" ) func run() { t:=time.NewTicker(time.Second * 5) //t.C 是一個(gè)管道 for v:=range t.C{ fmt.Println("hello",v) } } func main() { run() }
只運(yùn)行一次:
package main import ( "fmt" "time" ) func main() { select { case <- time.After(time.Second): fmt.Println("after") } }
超時(shí)控制 (可以用于檢測(cè)類(lèi)似MySQL查詢超時(shí)等):
package main import ( "time" "fmt" ) func queryDB(ch chan int) { time.Sleep(time.Second * 1000) ch <- 100 } func main() { ch :=make(chan int,5) go queryDB(ch) //設(shè)置主線程運(yùn)行時(shí)間, t := time.NewTicker(time.Second * 5 ) //隨機(jī)調(diào)度 select { //去ch中取,是否有數(shù)據(jù), case <-ch: fmt.Println("reslt") case <-t.C: fmt.Printf("timeout!!!") } }
讀寫(xiě)鎖:
寫(xiě)鎖:sync.Mutex 是互斥鎖, 多個(gè)線程修改數(shù)據(jù)的適合,只有一個(gè)線程可以修改
讀鎖:sync.RWMutex 讀鎖,多個(gè)線程同時(shí)讀一份數(shù)據(jù),可以并發(fā)的去執(zhí)行
Go中使用recover
應(yīng)?場(chǎng)景,如果某個(gè)goroutine panic了,?且這個(gè)goroutine??沒(méi)有捕獲(recover),那么整個(gè)進(jìn)程就會(huì)掛掉。所以,好的習(xí)慣是每當(dāng)go產(chǎn)??個(gè)goroutine,就需要寫(xiě)下recover
package main import ( "time" "fmt" ) func calc() { //捕獲異常 //必須寫(xiě)在最前面 defer func() { error :=recover() if error !=nil{ fmt.Println(error) } }() var p *int //p = new(int) *p = 100 } func main() { go calc() time.Sleep(time.Second * 2) fmt.Println("---") }
單元測(cè)試
分享名稱:Go(8[Goroutine|Channel|讀寫(xiě)鎖|異常處理])
標(biāo)題網(wǎng)址:http://chinadenli.net/article4/joigie.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站營(yíng)銷(xiāo)、域名注冊(cè)、企業(yè)網(wǎng)站制作、網(wǎng)站改版、自適應(yīng)網(wǎng)站、動(dòng)態(tài)網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)