<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
需求:要求統計1-900000000的數位中,那些是素數?
分析:
並行:因為是在一個CPU上,比如有10個執行緒,每個執行緒執行10毫秒(進行輪詢操作),從人的角度看,好像這10個執行緒都在執行,但是從微觀上看,在某一個時間點看,其實只有一個執行緒在執行,這就是並行。
並行:因為是在多個CPU上(比如有10個CPU),比如有10個執行緒,每個執行緒執行10毫秒(各自在不同CPU上執行),從人的角度看,這10個執行緒都在執行,但是從微觀上看,在某一個時間點看,也同時有10個執行緒在執行,這就是並行
Go主執行緒(有程式設計師直接稱為執行緒/也可以理解成程序):一個Go執行緒上,可以起多個攜程,你可以這樣理解,攜程是輕量的執行緒
Go協程的特點
有獨立的棧空間
共用程式堆空間
排程由使用者控制
攜程是輕量級的執行緒
案例說明
請編寫一個程式,完成如下功能:
1.在主執行緒(可以理解成程序)中,開啟一個goroutine,該攜程每隔1秒輸出“hello,world”
2.在主執行緒中也每隔一秒輸出“hello,golang”,輸出10次後,退出程式
3.要求主執行緒和goroutine同時執行
4.畫出主執行緒和協程執行流程圖
程式碼實現
// 在主執行緒(可以理解成程序)中,開啟一個goroutine,該協程每秒輸出 「hello,world」 // 在主執行緒中也每隔一秒輸出「hello,golang」,輸出10次後,退出程式 // 要求主執行緒和goroutine同時執行 //編寫一個函數,每隔1秒輸出 「hello,world」 func test(){ for i := 1;i<=10;i++{ fmt.Println("test() hello,world"+strconv.Itoa(i)) time.Sleep(time.Second) } } func main(){ go test() // 開啟了一個協程 for i:=1;i<=10;i++{ fmt.Println(" main() hello,golang"+strconv.Itoa(i)) time.Sleep(time.Second) } }
總結
MPG模式基本介紹
M:作業系統的主執行緒(是物理執行緒)
P:協程執行需要的上下文
G:協程
介紹:為了充分利用多CPU的優勢,在Golang程式中設定執行的CPU數目
package main import "fmt" import "runtime" func main(){ // 獲取當前系統CPU的數量 num := runtime.NumCPU() // 這裡設定num-1的CPU執行go程式 runtime.GOMAXPROCS(num) fmt.Println("num=",num) }
需求:現在要計算 1-200的各個數的階乘,並且把各個數的階乘放入到map中。最後顯示出來。要求使用goroutine完成
分析思路:
使用goroutine來完成,效率高,但是會出現並行/並行安全問題
這裡就提出了不同goroutine如何通訊的問題
程式碼實現
使用goroutine來完成(看看使用gorotine並行完成會出現什麼問題?然後我們會去解決)
在執行某個程式時,如何知道是否存在資源競爭問題,方法很簡單,在編譯該程式時,增加一個引數 -race即可
不同goroutine之間如何通訊
1.全域性變數的互斥鎖
2.使用管道channel來解決
使用全域性變數加鎖同步改程序式
原始碼
package main import ( "fmt" "time" "sync" ) // 需求:現在要計算 1-200的各個數的階乘,並且把各個數的階乘放入到map中 // 最後顯示出來。要求使用goroutine完成 // 思路 // 1. 編寫一個函數,來計算各個數的階乘,並放入到map中 // 2. 我們啟動的協程多個,統計的將結果放入到map中 // 3. map應該做出一個全域性的 var ( myMap = make(map[int]int,10) // 宣告一個全域性的互斥鎖 // lock 是一個全域性的互斥鎖 //sync 是包:synchornized 同步 // Mutex: 是互斥 lock sync.Mutex ) // test函數就是計算n!,讓將這個結果放入到myMap func test(n int){ res := 1 for i := 1;i<=n;i++{ res *= i } // 這裡我們將res放入到myMap // 加鎖 lock.Lock() myMap[n] = res // concurrent map writes? // 解鎖 lock.Unlock() } func main(){ // 我們這裡開啟多個協程完成這個任務[200個] for i := 1;i<=20;i++{ go test(i) } // 休眠10秒鐘【第二個問題】 time.Sleep(time.Second * 10) lock.Lock() // 這裡我們輸出結果 變數這個結果 for i,v := range myMap{ fmt.Printf("map[%d]=%dn",i,v) } lock.Unlock() }
channel(管道)-基本使用
channel初始化
說明:使用make進行初始化
var intChan chan int
intChan = make(chan int,10)
向channel中寫入(存放)資料
var intChan chan int
intChan = make(chan int,10)
num := 999
intChan <-10
intChan <-num
管道的初始化,寫入資料到管道,從管道讀取資料及基本的注意事項
package main import ( "fmt" ) func main(){ // 演示一下管道的使用 // 1.建立一個可以存放3個int型別的管道 var intChan chan int intChan = make(chan int,3) // 2.看看intChannel是什麼 fmt.Printf("intChan 的值=%v intChan本身的地址=%pn",intChan,&intChan) // 3.向管道寫入資料 intChan<- 10 num := 211 intChan<- num // 注意點,當我們給管寫入資料時,不能超過其容量 intChan<- 50 // intChan<- 98 //4. 看看管道的長度和cap(容量) fmt.Printf("channel len=%v cap=%v n",len(intChan),cap(intChan)) // 2,3 // 5.從管道中讀取資料 var num2 int num2 = <-intChan fmt.Println("num2=",num2) fmt.Printf("channel len=%v cap=%v n",len(intChan),cap(intChan)) // 2,3 // 6.在沒有使用協程的情況下,如果我們的管道資料已經全部取出,再取就會報告 deadlock num3 := <-intChan num4 := <-intChan // num5 := <-intChan fmt.Println("num3=",num3,"num4=",num4)//,"num5=",num5) }
channel使用的注意事項
1.channel中只能存放指定的資料型別
2.channel的資料放滿後,就不能再放入了
3.如果從channel取出資料後,可以繼續放入
4. 在沒有使用協程的情況下,如果channel資料取完了,再取,就會報dead lock
範例程式碼
package main import ( "fmt" ) type Cat struct{ Name string Age int } func main(){ // 定義一個存放任意資料型別的管道 3個資料 // var callChan chan interface{} allChan := make(chan interface{},3) allChan<- 10 allChan<- "tom jack" cat := Cat{"小花貓",4} allChan<- cat // 我們希望獲得到管道中的第三個元素,則先將前2個推出 <-allChan <-allChan newCat := <-allChan // 從管道中取出的Cat是什麼? fmt.Printf("newCat=%T,newCat=%vn",newCat,newCat) // 下面的寫法是錯誤的!編譯不通過 // fmt.Printf("newCat.Name=%v",newCat.Name) // 使用型別斷言 a := newCat.(Cat) fmt.Printf("newCat.Name=%v",a.Name) }
channel的關閉
使用內建函數close可以關閉channel,當channel關閉後,就不能再向channel寫資料了,但是仍然可以從該channel讀取資料
channel的遍歷
channel支援for-range的方式進行遍歷,請注意兩個細節
程式碼演示:
package main import ( "fmt" ) func main(){ intChan := make(chan int,3) intChan<- 100 intChan<- 200 close(intChan) // close // 這是不能夠再寫入到channel // intChan<-300 fmt.Println("okook~") // 當管道關閉後,讀取資料是可以的 n1 := <-intChan fmt.Println("n1=",n1) // 遍歷管道 intChan2 := make(chan int,100) for i := 0; i< 100;i++{ intChan2<-i*2 // 放入100個資料到管道 } // 遍歷管道不能使用普通的for迴圈 // 在遍歷時,如果channel沒有關閉,則會出現deadlock的錯誤 // 在遍歷時,如果channel已經關閉,則會正常遍歷資料,遍歷完後,就會退出遍歷 close(intChan2) for v := range intChan2{ fmt.Println("v=",v) } }
到此這篇關於Golang中goroutine和channel使用介紹深入分析的文章就介紹到這了,更多相關Go goroutine與channel內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45