GoLang Go 程

📢 本文由 gemini-3-flash-preview 翻譯

Golang Series

Hello GoLang: https://blog.yexca.net/archives/154
GoLang (var and const) 變數與常數: https://blog.yexca.net/archives/155
GoLang (func) 函式: https://blog.yexca.net/archives/156
GoLang (slice and map) 切片: https://blog.yexca.net/archives/160
GoLang (OOP) 物件導向: https://blog.yexca.net/archives/162
GoLang (reflect) 反射: https://blog.yexca.net/archives/204
GoLang (struct tag) 結構體標籤: https://blog.yexca.net/archives/205
GoLang (goroutine) Go 程: 本文
GoLang (channel) 通道: https://blog.yexca.net/archives/207


行程 (Process) -> 執行緒 (Thread) -> 協程 (Coroutine)

協程 (coroutine) 也稱為輕量級執行緒,可以輕鬆建立上萬個而不會導致系統資源耗盡,多個協程共享該執行緒分配到的電腦資源。

Go 語言原生支援協程,稱為 goroutine,Go 的並發透過 goroutine 和 channel 實作。

建立 goroutine

透過 go 關鍵字開啟一個 goroutine

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
    "fmt"
    "time"
)

func newTask() {
    i := 0
    for {
        fmt.Println("newTask goroutine i =", i)
        i++
        time.Sleep(1 * time.Second)
    }
}

func main() {
    go newTask()

    i := 0
    for {
        fmt.Println("main goroutine i =", i)
        i++
        time.Sleep(1 * time.Second)
    }
}

使用匿名函式

當然也可以使用匿名函式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import (
    "fmt"
    "time"
)

func main() {
    go func() {
        defer fmt.Println("A.defer")
        func() {
            defer fmt.Println("B.defer")

            fmt.Println("B")
        }() // 表示執行該匿名函式

        fmt.Println("A")
    }()

    time.Sleep(2 * time.Second)
}

匿名函式也可以有參數與回傳值,不過 goroutine 的回傳值需要透過 channel 傳輸,下例僅示範帶有參數的情況:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
package main

import (
    "fmt"
    "time"
)

func main() {
    go func(a, b int) {
        fmt.Println("a =", a, "b =", b)
    }(10, 20)

    time.Sleep(2 * time.Second)
}

結束

主 goroutine 結束後,其他的工作 goroutine 也會自動結束。

不過也可以使用 runtime.Goexit() 立即終止當前 goroutine 的執行 (defer 仍會執行)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
    "fmt"
    "runtime"
    "time"
)

func main() {
    go func() {
        defer fmt.Println("A.defer")
        func() {
            defer fmt.Println("B.defer")
            runtime.Goexit() // 結束 goroutine
            fmt.Println("B")
        }() // 表示執行該匿名函式

        fmt.Println("A")
    }()

    time.Sleep(2 * time.Second)
}

/*
 * 輸出
 * B.defer
 * A.defer
 */