日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Go基础--goroutine和channel

發布時間:2025/3/19 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Go基础--goroutine和channel 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

goroutine

在go語言中,每一個并發的執行單元叫做一個goroutine

這里說到并發,所以先解釋一下并發和并行的概念:

并發:邏輯上具備同時處理多個任務的能力

并行:物理上在同一時刻執行多個并發任務

當一個程序啟動時,其主函數即在一個單獨的goroutine中運行,一般這個goroutine是主goroutine

如果想要創建新的goroutine,只需要再執行普通函數或者方法的的前面加上關鍵字go

通過下面一個例子演示并發的效果,主goroutine會計算第45個斐波那契函數,在計算的同時會循環打印:-\|/??

這里需要知道:當主goroutine結束之后,所有的goroutine都會被打斷,程序就會退出

package mainimport ("time""fmt" )func spinner(delay time.Duration){for {for _,r := range `-\|/`{fmt.Printf("\r%c",r)time.Sleep(delay)}} }func fib(x int) int{// 斐波那契函數if x < 2{return x}return fib(x-1) + fib(x-2) }func main() {go spinner(100*time.Millisecond) //開啟一個goroutineconst n = 45fibN:= fib(n)fmt.Printf("\rFib(%d) = %d\n",n,fibN) }

當第一次看到go的并發,感覺真是太好用了!!!!

所以在網絡編程里,服務端都是需要同時可以處理很多個連接,我們看一下下面的服務端和客戶端例子

服務端:

package mainimport ("net""io""time""log" )func handleConn(c net.Conn){defer c.Close()for{_,err := io.WriteString(c,time.Now().Format("15:04:05\r\n"))if err != nil{return}time.Sleep(1*time.Second)} }func main() {// 監聽本地tcp的8000端口listener,err := net.Listen("tcp","localhost:8000")if err != nil{log.Fatal(err)}for {conn,err := listener.Accept()if err!= nil{log.Print(err)continue}go handleConn(conn)} }

客戶端:

package mainimport ("io""log""net""os" )func mustCopy(dst io.Writer,src io.Reader){// 從連接中讀取內容,并寫到標準輸出if _,err := io.Copy(dst,src);err !=nil{log.Fatal(err)}}func main(){conn,err := net.Dial("tcp","localhost:8000")if err != nil{log.Fatal(err)}defer conn.Close()mustCopy(os.Stdout, conn) }

Channel

channel是不同的goroutine之間的通信機制。

一個goroutine通過channel給另外一個goroutine發送信息。

每個channel 都有一個特殊的類型,也就是channel可以發送的數據的類型

我們可以通過make創建一個channel如:

ch := make(chan int)? 這就是創建了一個類型為int的channel

默認我們這樣創建的是無緩存的channel,當然我們可以通過第二個參數來設置容量

ch := make(chan int,10)

注意:channel是引用類型,channel的零值也是nil

兩個相同類型的channel可以使用==運算符比較。如果兩個channel引用的是相通的對象,那么比較的結
果為真。一個channel也可以和nil進行比較。

因為channel是在不同的goroutine之間進行通信的,所以channel這里有兩種操作:存數據和取數據,而這里兩種操作的

方法都是通過運算符:<-

ch <- x? 這里是發送一個值x到channel中

x = <- ch 這里是從channel獲取一個值存到變量x

<-ch 這里是從channel中取出數據,但是不使用結果

close(ch) 用于關閉channel

當我們關閉channel后,再次發送就會導致panic異常,但是如果之前發送過數據,我們在關閉channel之后依然可以執行接收操作

如果沒有數據的話,會產生一個零值

?

基于channel發送消息有兩個重要方面,首先每個消息都有一個值,但是有時候通訊的事件和發送的時刻也同樣重要。

我們更希望強調通訊發送的時刻時,我們將它稱為消息事件。有些消息并不攜帶額外的信息,它僅僅是用做兩個goroutine之間的同步,這個時候我們可以用struct{}空結構體作為channel元素的類型

?

?

?

?無緩存的channel

基于無緩存的channel的發送和接受操作將導致兩個goroutine做一次同步操作,所以無緩存channel有時候也被稱為同步channel

串聯的channel (Pipeline)

channel也可以用于多個goroutine連接在一起,一個channel的輸出作為下一個channel的輸入,這種串聯的channel就是所謂的pipeline

通過下面例子理解,第一個goroutine是一個計算器,用于生成0,1,2...形式的整數序列,然后通過channel將該整數序列

發送給第二個goroutine;第二個goroutine是一個求平方的程序,對收到的每個整數求平方,然后將平方后的結果通過第二個channel發送給第三個goroutine

第三個goroutine是一個打印程序,打印收到的每個整數

package mainimport ("fmt" )func main(){naturals := make(chan int)squares := make(chan int)go func(){for x:=0;;x++{naturals <- x}}()go func(){for {x := <- naturalssquares <- x * x}}()for{fmt.Println(<-squares)} }

但是如果我把第一個生成數的寫成一個有范圍的循環,這個時候程序其實會報錯的

所以就需要想辦法讓發送知道沒有可以發給channel的數據了,也讓接受者知道沒有可以接受的數據了

這個時候就需要用到close(chan)

當一個channel被關閉后,再向該channel發送數據就會導致panic異常

當從一個已經關閉的channel中接受數據,在接收完之前發送的數據后,并不會阻塞,而會立刻返回零值,所以在從channel里接受數據的時候可以多獲取一個值如:

go func(){
for {
x ,ok := <-naturals
if !ok{
break
}
squares <- x*x
}
close(squares)
}()

第二位ok是一個布爾值,true表示成功從channel接受到值,false表示channel已經被關閉并且里面沒有值可以接收

單方向的channel

當一個channel座位一個函數的參數時,它一般總是被專門用于只發送或者只接收

chan <- int :表示一個只發送int的channel,只能發送不能接收

< chan int : 表示一個只接受int的channel,只能接收不能發送

?

當然在有時候我們需要獲取channel內部緩存的容量,可以通過內置的cap函數獲取

而len函數則返回的是channel內實際有效的元素個數

基于select的多路復用

?這里先說一個擁有的知識點:time.Tick函數

這個函數返回一個channel,通過下面代碼進行理解:

package mainimport ("time""fmt" )func main() {tick := time.Tick(1*time.Second)for countdown :=10;countdown>0;countdown--{j :=<- tickfmt.Println(j)} }

程序會循環打印一個時間戳

?

select 語句:

select {case <-ch1:// ...case x := <-ch2:// ...use x...case ch3 <- y:// ...default: // ...
}

select語句的形式其實和switch語句有點類似,這里每個case代表一個通信操作

在某個channel上發送或者接收,并且會包含一些語句組成的一個語句塊 。

select中的default來設置當 其它的操作都不能夠馬上被處理時程序需要執行哪些邏輯

channel 的零值是nil,? 并且對nil的channel 發送或者接收操作都會永遠阻塞,在select語句中操作nil的channel永遠都不會被select到。

這可以讓我們用nil來激活或者禁用case,來達成處理其他輸出或者輸出時間超時和取消的邏輯

?

所有的努力都值得期許,每一份夢想都應該灌溉!

總結

以上是生活随笔為你收集整理的Go基础--goroutine和channel的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。