目錄
Goroutine
基本用法
channel
channel 的基本操作
帶緩衝channel 與無緩衝channel
聲明channel 的只發送類型和只接收類型
channel 的关闭
小结
首頁 後端開發 Golang 初探Go語言中的Goroutine與channel

初探Go語言中的Goroutine與channel

Feb 02, 2023 pm 08:18 PM
golang go語言

這篇文章帶大家初步了解Go語言中的Goroutine和channel,希望對大家有幫助!

初探Go語言中的Goroutine與channel

Go 語言的CSP 並發模型的實作包含兩個主要組成部分:一個是Goroutine,另一個是channel。本文將會介紹它們的基本用法和注意事項。

Goroutine

GoroutineGo 應用程式的基本執行單元,它是一種輕量級的用戶級線程,其底層是透過coroutine(協程)去實現的並發。眾所周知,協程是一種運行在用戶狀態的使用者線程,因此 Goroutine 也是被調度於 Go 程式運行時。

基本用法

語法:go 函數/方法

透過go 關鍵字函數/方法可以建立一個Goroutine

程式碼範例:

import (
   "fmt"
   "time"
)

func printGo() {
   fmt.Println("具名函数")
}

type G struct {
}

func (g G) g() {
   fmt.Println("方法")
}

func main() {
   // 基于具名函数创建 goroutine
   go printGo()
   // 基于方法创建 goroutine
   g := G{}
   go g.g()
   // 基于匿名函数创建 goroutine
   go func() {
      fmt.Println("匿名函数")
   }()
   // 基于闭包创建 goroutine
   i := 0
   go func() {
      i++
      fmt.Println("闭包")
   }()
   time.Sleep(time.Second) // 避免 main goroutine 结束后,其创建的 goroutine 来不及运行,因此在此休眠 1 秒
}
登入後複製

執行結果:

闭包
具名函数
方法
匿名函数
登入後複製

當多個 Goroutine 存在時,它們的執行順序是不固定的。因此每次列印的結果都不相同。

由程式碼可知,透過go 關鍵字,我們可以基於具名函數 / 方法 建立goroutine,也可以基於匿名函數 / 閉包 建立goroutine

那麼 Goroutine 是如何退出的呢?正常情況下,只要 Goroutine 函數執行結束,或執行返回,意味著 Goroutine 的退出。如果 Goroutine 的函數或方法有回傳值,在 Goroutine 退出時會將其忽略。

channel

channel 在 Go 並發模型中扮演者重要的角色。它可以用來實現 Goroutine 間的通信,也可以用來實現 Goroutine 間的同步。

channel 的基本操作

channel 是一種複合資料類型,宣告時需要指定channel 裡元素的類型。

宣告語法:var ch chan string

透過上述程式碼宣告一個元素類型為stringchannel,其只能存放string 類型的元素。 channel 是引用類型,必須初始化才能寫入數據,透過 make 的方式初始化。

import (
   "fmt"
)

func main() {
   var ch chan string
   ch = make(chan string, 1)
   // 打印 chan 的地址
   fmt.Println(ch)
   // 向 ch 发送 "Go" 数据
   ch <- "Go"
   // 从 ch 中接收数据
   s := <-ch
   fmt.Println(s) // Go
}
登入後複製

透過ch <- xxx 可以向channel 變數ch 發送數據,透過x := <- ch 可以從channel 變數ch 接收資料。

帶緩衝channel 與無緩衝channel

如果初始化#channel 時,不指定容量時,則建立的是一個無緩衝的channel

ch := make(chan string)
登入後複製

無緩衝的channel 的發送與接收操作是同步的,在執行發送操作之後,對應Goroutine 將會阻塞,直到有另一個Goroutine 去執行接收操作,反之亦然。如果將發送操作和執行操作放在同一個 Goroutine 下進行,會發生什麼操作?看看下述程式碼:

import (
   "fmt"
)

func main() {
   ch := make(chan int)
   // 发送数据
   ch <- 1 // fatal error: all goroutines are asleep - deadlock!
   // 接收数据
   n := <-ch
   fmt.Println(n)
}
登入後複製

程式運行之後,會在ch <- 處得到fatal error,提示所有的Goroutine處於休眠狀態,也就是死鎖了。為避免這種情況,我們需要將 channel 的傳送操作和接收操作放到不同的 Goroutine 中執行。

import (
   "fmt"
)

func main() {
   ch := make(chan int)
   go func() {
      // 发送数据
      ch <- 1
   }()
   // 接收数据
   n := <-ch
   fmt.Println(n) // 1
}
登入後複製

由上述例子可以下結論:無緩衝channel 的發送與接收操作,一定要放在兩個不同的Goroutine 中進行,否則會發生deadlock 形象。


如果指定容量,則建立的是一個帶有緩衝的channel

ch := make(chan string, 5)
登入後複製

有緩衝的channel 與無緩衝的chennel 有所區別,執行發送操作時,只要channel 的緩衝區未滿,Goroutine 不會掛起,直到緩衝區滿時,再向channel 執行發送操作,才會導致Goroutine 掛起。程式碼範例:

func main() {
   ch := make(chan int, 1)
   // 发送数据
   ch <- 1

   ch <- 2 // fatal error: all goroutines are asleep - deadlock!
}
登入後複製

聲明channel 的只發送類型和只接收類型

  • 既能發送又能接收的channel

    ch := make(chan int, 1)
    登入後複製

    透過上述程式碼獲得channel 變量,我們可以對它執行發送與接收的操作。

  • 只接收的channel

    ch := make(<-chan int, 1)
    登入後複製

    透過上述程式碼獲得channel 變量,我們只能對它進行接收操作。

  • 只發送的channel

    ch := make(chan<- int, 1)
    登入後複製

    透過上述程式碼獲得channel 變量,我們只能對它進行發送操作。

通常只发送 channel 类型和只接收 channel 类型,会被用作函数的参数类型或返回值:

func send(ch chan<- int) {
   ch <- 1
}

func recv(ch <-chan int) {
   <-ch
}
登入後複製

channel 的关闭

通过内置函 close(c chan<- Type),可以对 channel 进行关闭。

  • 在发送端关闭 channel

    channel 关闭之后,将不能对 channel 执行发送操作,否则会发生 panic,提示 channel 已关闭。

    func main() {
       ch := make(chan int, 5)
       ch <- 1
       close(ch)
       ch <- 2 // panic: send on closed channel
    }
    登入後複製
  • 管道 channel 之后,依旧可以对 channel 执行接收操作,如果存在缓冲区的情况下,将会读取缓冲区的数据,如果缓冲区为空,则获取到的值为 channel 对应类型的零值。

    import "fmt"
    
    func main() {
       ch := make(chan int, 5)
       ch <- 1
       close(ch)
       fmt.Println(<-ch) // 1
       n, ok := <-ch
       fmt.Println(n)  // 0
       fmt.Println(ok) // false
    }
    登入後複製
  • 如果通过 for-range 遍历 channel 时,中途关闭 channel 则会导致 for-range 循环结束。

  • 小结

    本文首先介绍了 Goroutine的创建方式以及其退出的时机是什么。

    其次介绍了如何创建 channel 类型变量的有缓冲与无缓冲的创建方式。需要注意的是,无缓冲的 channel 发送与接收操作,需要在两个不同的 Goroutine 中执行,否则会发送 error

    接下来介绍如何定义只发送和只接收的 channel 类型。通常只发送 channel 类型和只接收 channel 类型,会被用作函数的参数类型或返回值。

    最后介绍了如何关闭 channel,以及关闭之后的一些注意事项。

    【相关推荐:Go视频教程编程教学

    以上是初探Go語言中的Goroutine與channel的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1665
14
CakePHP 教程
1424
52
Laravel 教程
1321
25
PHP教程
1269
29
C# 教程
1249
24
在Go語言中使用Redis Stream實現消息隊列時,如何解決user_id類型轉換問題? 在Go語言中使用Redis Stream實現消息隊列時,如何解決user_id類型轉換問題? Apr 02, 2025 pm 04:54 PM

Go語言中使用RedisStream實現消息隊列時類型轉換問題在使用Go語言與Redis...

GoLand中自定義結構體標籤不顯示怎麼辦? GoLand中自定義結構體標籤不顯示怎麼辦? Apr 02, 2025 pm 05:09 PM

GoLand中自定義結構體標籤不顯示怎麼辦?在使用GoLand進行Go語言開發時,很多開發者會遇到自定義結構體標籤在�...

Go語言中哪些庫是由大公司開發或知名的開源項目提供的? Go語言中哪些庫是由大公司開發或知名的開源項目提供的? Apr 02, 2025 pm 04:12 PM

Go語言中哪些庫是大公司開發或知名開源項目?在使用Go語言進行編程時,開發者常常會遇到一些常見的需求,�...

Golang的目的:建立高效且可擴展的系統 Golang的目的:建立高效且可擴展的系統 Apr 09, 2025 pm 05:17 PM

Go語言在構建高效且可擴展的系統中表現出色,其優勢包括:1.高性能:編譯成機器碼,運行速度快;2.並發編程:通過goroutines和channels簡化多任務處理;3.簡潔性:語法簡潔,降低學習和維護成本;4.跨平台:支持跨平台編譯,方便部署。

在Go編程中,如何正確管理Mysql和Redis的連接與釋放資源? 在Go編程中,如何正確管理Mysql和Redis的連接與釋放資源? Apr 02, 2025 pm 05:03 PM

Go編程中的資源管理:Mysql和Redis的連接與釋放在學習Go編程過程中,如何正確管理資源,特別是與數據庫和緩存�...

Golang vs. Python:性能和可伸縮性 Golang vs. Python:性能和可伸縮性 Apr 19, 2025 am 12:18 AM

Golang在性能和可擴展性方面優於Python。 1)Golang的編譯型特性和高效並發模型使其在高並發場景下表現出色。 2)Python作為解釋型語言,執行速度較慢,但通過工具如Cython可優化性能。

多進程日誌寫入如何保證並發安全又高效? 多進程日誌寫入如何保證並發安全又高效? Apr 02, 2025 pm 03:51 PM

高效處理多進程日誌寫入的並發安全問題多進程同時寫入同一個日誌文件,如何保證並發安全且高效?這是一個...

使用Go語言連接Oracle數據庫時是否需要安裝Oracle客戶端? 使用Go語言連接Oracle數據庫時是否需要安裝Oracle客戶端? Apr 02, 2025 pm 03:48 PM

使用Go語言連接Oracle數據庫時是否需要安裝Oracle客戶端?在使用Go語言開發時,連接Oracle數據庫是一個常見需求�...

See all articles