go 協程
package main
import "fmt"
func f(from string) {
for i := 0; i < 3; i++ {
fmt.Println(from, ":", i)
}
}
func main() {
// 正常調用方法
f("normal")
// 協程
// go f()
go f("go")
// go 匿名函數(going)
go func(msg string) {
fmt.Println(msg)
}("going")
// 等待輸入,我們阻塞一下
// 如果不阻塞,協程來不及執行,主程序就會退出了
var input string
fmt.Scanln(&input)
fmt.Println("done")
}
管道
管道用來連接多個協程,收發數據
package main
import "fmt"
func main() {
// 創建一個管道
// 管道中傳輸的數據是string, 管道使用chan關鍵字
messages := make(chan string)
// 看箭頭的方向, 下面的是向管道內輸入數據
go func() { messages <- "ping" }()
// 從管道中接收數據
msg := <-messages
fmt.Println(msg)
}
// 默認發送和接收操作是阻塞的,直到發送方和接收方都準備完畢。
緩衝管道
緩衝管道與普通無緩衝管道的區別
簡單說 緩衝管道,可以設定管道可存信息的大小
無緩衝普通的,大小就是1,有一個消息不取出就無法再次放入
ps: 測試是無緩衝管道,連續放入兩個編譯或執行的時候會報錯
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
https://blog.csdn.net/sgsgy5/article/details/82054902
package main
import "fmt"
func main() {
// 設置緩衝管道大小2
messages := make(chan string, 2)
// 發送
messages <- "buffered"
messages <- "channel"
// 接收
fmt.Println(<-messages)
fmt.Println(<-messages)
}
管道同步
package main
import "fmt"
import "time"
func worker(done chan bool) {
fmt.Print("working...\n") // fmt.Print 不會換行,而Println會換行
time.Sleep(time.Second)
fmt.Println("done")
// 發送一個值來通知我們已經完工啦。
done <- true
}
func main() {
// 創建管道,管道容量1 接收參數布爾類型
// 用這個管道阻塞住主進程,這樣就可以其到協程管道同步的效果了
done := make(chan bool, 1)
go worker(done)
// 阻塞住,直到worker協程執行完畢後向管道中發送消息
<-done
}
管道方向
select case
管道chan作爲參數 傳入到函數時
可以規定這個管道 只能發 或 只能收,當然還可以不做限制
package main
import "fmt"
// pings是管道,通過箭頭的方向,我們可以猜到 這個限制的是 只能向管道里傳入值
// 也就是隻能發chan-<
// 如果這樣 <-chan 就行只能收
func ping(pings chan<- string, msg string) {
pings <- msg
}
// 兩個管道,一個只能發,一個只能收
func pong(pings <-chan string, pongs chan<- string) {
msg := <-pings
pongs <- msg
}
func main() {
pings := make(chan string, 1)
pongs := make(chan string, 1)
ping(pings, "passed message")
pong(pings, pongs)
fmt.Println(<-pongs)
}
管道選擇器
select…case
管道選擇器可以讓我們同時等待多個管道操作
通常 go協程+管道+管道選擇器 結合是Go一個強大的特性
感覺和python的異步協程中的loop差不多
package main
import "time"
import "fmt"
func main() {
// 創建2個管道
c1 := make(chan string)
c2 := make(chan string)
// go協程 執行匿名函數,休眠1秒,傳入one
go func() {
time.Sleep(time.Second * 1)
c1 <- "one"
}()
// 休眠2秒,傳入two
go func() {
time.Sleep(time.Second * 2)
c2 <- "two"
}()
// 使用關鍵字 select..case
// 哪個先完成,就先執行哪個case,然後向下執行
// 所以我們這裏循環了2次,目的是讓他們都得到執行,最後耗時應該是2秒多一點點,不會是3秒
for i := 0; i < 2; i++ {
select {
case msg1 := <-c1:
fmt.Println("received", msg1)
case msg2 := <-c2:
fmt.Println("received", msg2)
}
}
}