go 协程
概述
? ? ? ? ??Go協程(Goroutine)是與其他函數或方法同時運行的函數或方法。可以認為Go協程是輕量級的線程。與創建線程相比,創建Go協程的成本很小。因此在Go中同時運行上千個協程是很常見的。
?
Go協程對比線程的優點
-
與線程相比,Go協程的開銷非常小。Go協程的堆棧大小只有幾kb,它可以根據應用程序的需要而增長和縮小,而線程必須指定堆棧的大小,并且堆棧的大小是固定的。
-
Go協程被多路復用到較少的OS線程。在一個程序中數千個Go協程可能只運行在一個線程中。如果該線程中的任何一個Go協程阻塞(比如等待用戶輸入),那么Go會創建一個新的OS線程并將其余的Go協程移動到這個新的OS線程。所有這些操作都是 runtime 來完成的,而我們程序員不必關心這些復雜的細節,只需要利用 Go 提供的簡潔的 API 來處理并發就可以了。
-
Go 協程之間通過信道(channel)進行通信。信道可以防止多個協程訪問共享內存時發生竟險(race condition)。信道可以想象成多個協程之間通信的管道。
goroutine 可能切換的點
-
非強占式
-
I/O ,select
-
channel
-
等待鎖
-
調用函數
-
runtime.Gosched()
-
只是參考,不能保證切換
代碼一
package mainimport ("fmt""time" )func sample(message chan string) {message <- "hello goroutine!1"message <- "hello goroutine!2"message <- "hello goroutine!3"message <- "hello goroutine!4" }func sampleTwo(message chan string) {time.Sleep(2 * time.Second)str := <-messagestr = str + "I am goroutinetwo"message <- strclose(message) }func main() {/*** 隊列為3的*/var message = make(chan string, 3)go sample(message)go sampleTwo(message)time.Sleep(3 * time.Second)str := <-messagefmt.Println(str)fmt.Println(<-message)for strTemp := range message {fmt.Println(strTemp)}}代碼二
? ??select 多個隊列的隨機選擇
package mainimport ("strconv""time""fmt" )func sample(ch chan string) {for i := 0; i < 19; i++ {ch <- "I am sample num :" + strconv.Itoa(i)time.Sleep(1 * time.Second)} }func sampleTwo(ch chan int) {for i := 0; i < 10; i++ {ch <- itime.Sleep(2 * time.Second)} }func main() {/*** 隊列為3的*/var ch1 = make(chan string, 3)var ch2 = make(chan int, 5)for i := 0; i < 10; i++ {go sample(ch1)go sampleTwo(ch2)}// select 多個隊列的隨機選擇for i := 0; i < 1000; i++ {select {case str, ch1Check := <-ch1:if !ch1Check {fmt.Println("ch1Check false")}fmt.Println(str)case p, ch2Check := <-ch2:if !ch2Check {fmt.Println("ch2Check false")}fmt.Println(p)}}time.Sleep(60 * time.Second) }加大兩個sample的時間差
?
package mainimport ("strconv""time""fmt" )func sample(ch chan string) {for i := 0; i < 19; i++ {ch <- "I am sample num :" + strconv.Itoa(i)time.Sleep(3 * time.Second)} }func sampleTwo(ch chan int) {for i := 0; i < 10; i++ {ch <- itime.Sleep(60 * time.Second)} }func main() {/*** 隊列為3的*/var ch1 = make(chan string, 3)var ch2 = make(chan int, 5)for i := 0; i < 10; i++ {go sample(ch1)go sampleTwo(ch2)}// select 多個隊列的隨機選擇for {select {case str, ch1Check := <-ch1:if !ch1Check {fmt.Println("ch1Check false")}fmt.Println(str)case p, ch2Check := <-ch2:if !ch2Check {fmt.Println("ch2Check false")}fmt.Println(p)}}}參考:
https://www.yuque.com/docs/share/999e271e-2418-44c9-a9ff-8fc30aef8e96
總結
- 上一篇: Cydia无法联网
- 下一篇: 在Ubuntu18.04中安装ROS教程