iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 7
2
Software Development

Go Phishing!30 天用 Go 實作 Reverse Proxy 之釣魚大作戰系列 第 7

Day07-Go 語法 III

前面兩天講的都是基本的語法,Go 有的其他語言也有,但今天要說的 Goroutine 跟 Channel 就是 Go 才有的特性了,也是 Go 最厲害的地方

Goroutine

go func(...) 可以把一個 function 跑在不同的 Goroutine 上,Goroutine 跟 Thread 在概念上很像,可以想像成高效能的 Thread,同時開上千上萬個 Goroutine 都沒什麼問題

Run

啟動一個 goroutine 的方法是 go func(...),這邊建議搭配下圖一起看,剛開始只有一個 main goroutine,後來 go say(...) 啟動了兩個 goroutine,G1 等待 200ms 然後輸出 World,G2 等待 100ms 輸出 Hello,所以最後輸出會是 HelloWorld

因為只要 main goroutine 結束整個程式就會結束,所以就讓他等 300ms 讓 G1、G2 都跑完

import "time"

func say(s string, delay time.Duration) {
    time.Sleep(delay)
    fmt.Print(s)
}

func main() {
    go say("World", 200 * time.Millisecond) // 啟動一個 goroutine,叫 G1
    go say("Hello", 100 * time.Millisecond) // 又啟動一個 goroutine,叫 G2
    time.Sleep(300 * time.Millisecond)
}

Channel

Channel 可以想像成是一條通道,方便在 goroutine 之間傳遞資料。c := make(chan int) 就是初始化一條可以傳輸 int 的通道,這條通道的型別是 chan intc <- 6 是把值塞進去通道裡面,而 x := <-c 則是從通道中拿出值放到 x 變數裡面

     -------------
x <- |  Channel  |  <- 6
     -------------

在下面的例子中先初始化一個 channel,然後把陣列切成左右兩邊給不同的 goroutine 去做加總,加總完把結果塞進去通道裡面(c <- sum),main goroutine 在通道的另外一端收到後(x := <-c)再把兩個結果相加

Run

func sum(s []int, c chan int) {
    sum := 0
    for _, v := range s {
        sum += v
    }
    c <- sum // send sum to channel
    
    // -------------
    // |  Channel  |  <- sum
    // -------------
}

func main() {
    s := []int{1, 2, 3, 4, 5, 6}

    c := make(chan int)
    go sum(s[:len(s)/2], c)
    go sum(s[len(s)/2:], c)

    // receive from channel
    //      -------------
    // x <- |  Channel  |
    //      -------------
    
    x := <-c
    y := <-c

    fmt.Printf("%d + %d = %d", x , y, x+y)
    // 6 + 15 = 21
}

小結

今天講的 Goroutine 跟 Channel 因為涉及併發,不太像人腦平常的思考方式XD,所以會比較難懂,可以多看幾次圖,都沒問題的話明天就開始實作囉


上一篇
Day06-Go 語法 II
下一篇
Day08-動手架一個 HTTP Server
系列文
Go Phishing!30 天用 Go 實作 Reverse Proxy 之釣魚大作戰30

尚未有邦友留言

立即登入留言