並行計算

一、Goroutine協程:協程就是go提供的輕量級的獨立運算過程,比線程還輕;建立一個協程,就是使用go關鍵字,後面跟上要運行的函數異步

案例要求:1)、先計算1000如下全部可以被3整除的整數的和Aide

     2)、而後計算1000如下全部可以被5整除的整數和B函數

     3)、而後再計算1000如下全部可以被3和5整除的整數和Cspa

     4)、使用A+B-C獲得最後結果線程

案例中,使用go關鍵字建立一個協程,協程函數內使用channel(chan數據,相似隊列,在取chan中數據時,若是爲空,會阻塞,直到chan中有數據)存儲數據code

package main

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

func get_sum_of_divisible(num int, divider int, resultChan chan int) {
    sum := 0
    for value := 0; value < num; value++ {
        if value%divider == 0 {
            sum += value
        }
    }
    resultChan <- sum
}

func main() {
    runtime.GOMAXPROCS(runtime.NumCPU())
    LIMIT := 1000
    //用於被15除結果
    job1 := make(chan int, 1)
    //用於被3,5除結果
    job2 := make(chan int, 2)

    t_start := time.Now()
    go get_sum_of_divisible(LIMIT, 15, job1)
    go get_sum_of_divisible(LIMIT, 3, job2)
    go get_sum_of_divisible(LIMIT, 5, job2)

    sum15 := <-job1
    sum3, sum5 := <-job2, <-job2

    sum := sum3 + sum5 - sum15
    t_end := time.Now()
    fmt.Println(sum)
    fmt.Println(t_end.Sub(t_start))
}

二、Channel通道:提供了協程之間的通訊方式以及運行同步機制協程

案例:假設訓練定點投籃和三分投籃,教練在計數blog

若是向channel裏面寫信息,必須有配對的取信息的一端;假如把下面的go count(c)註釋掉,則不會有打印數據three

package main

import (
    "fmt"
    "strconv"
    "time"
)

func fixed_shooting(msg_chan chan string) {
    i := 1
    for {
        msg_chan <- "fixed shooting"
        var str string = strconv.Itoa(i)
        fmt.Println("continue fixed shooting..." + str)
        i++
    }
}

func count(msg_chan chan string) {
    for {
        msg := <-msg_chan
        fmt.Println(msg)
        time.Sleep(time.Second * 1)
    }
}

func main() {
    var c chan string
    c = make(chan string)

    go fixed_shooting(c)
    go count(c)

    var input string
    fmt.Scanln(&input)
}

加一個三分投籃方法,能夠看出,寫入channel中的數據,必須讀取出來才能再次寫入,若是沒有讀取出來,再次寫入會失敗隊列

package main

import (
    "fmt"
    "strconv"
    "time"
)

func three_point_shooting(msg_chan chan string) {
    i := 1
    for {
        var str string = strconv.Itoa(i)
        msg_chan <- "three point shooting--" + str
        i++
    }
}

func fixed_shooting(msg_chan chan string) {
    i := 1
    for {
        var str string = strconv.Itoa(i)
        msg_chan <- "fixed shooting--" + str
        i++
    }
}

func count(msg_chan chan string) {
    for {
        msg := <-msg_chan
        fmt.Println(msg)
        time.Sleep(time.Second * 1)
    }
}

func main() {
    var c chan string
    c = make(chan string)

    go fixed_shooting(c)
    go three_point_shooting(c)
    go count(c)

    var input string
    fmt.Scanln(&input)
}

結果圖以下,結果是交替輸出的,也就是channel中輸入的必須輸出後才能再次輸入

三、Channel通道方向

var c chan string  可讀寫channel,可寫入也可讀取

var c chan<- string  只寫channel,只能寫入

var c <-chan string  只讀channel,只能讀取

四、多通道(Select)

案例中,select依次檢查每一個channel是否有消息傳遞過來,若是有就輸出;若是同時有多個消息到達,select隨機選擇一個channel來從中讀取消息;若是沒有一個channel有消息到達,那麼select語句就阻塞在這裏一直等待。select 語句也能夠有default片斷,case不符合時會執行default語句片斷。select中case、default相似switch中case、default

下面case中使用了time.After,能夠這樣理解,main函數也是一個channel,time.After讓main阻塞指定時間後,讀出時間消息(案例中沒有用變量存儲返回的時間)

package main

import (
    "fmt"
    "time"
)

func fixed_shooting(msg_chan chan string) {
    var times = 3
    var t = 1
    for {
        if t <= times {
            msg_chan <- "fixed shooting"
        }
        t++
        time.Sleep(time.Second * 1)
    }
}

func three_point_shooting(msg_chan chan string) {
    var times = 3
    var t = 1
    for {
        if t <= times {
            msg_chan <- "three point shooting"
        }
        t++
        time.Sleep(time.Second * 1)
    }
}

func main() {
    c_fixed := make(chan string)
    c_3_point := make(chan string)

    go fixed_shooting(c_fixed)
    go three_point_shooting(c_3_point)

    go func() {
        for {
            select {
            case msg1 := <-c_fixed:
                fmt.Println(msg1)
            case msg2 := <-c_3_point:
                fmt.Println(msg2)
            case <-time.After(time.Second * 5):
                fmt.Println("timeout check again...")
            }
        }
    }()

    var input string
    fmt.Scanln(&input)
}

結果圖

五、Channel Buffer通道緩衝區:通常咱們定義的channel都是同步的,也就是說接受端和發送端彼此等待對方OK纔開始。可是若是執行了channel緩衝區大小,那麼消息的發送和接收是異步的,除非channel緩衝區已經滿了

package main

import (
    "fmt"
    "strconv"
    "time"
)

func shooting(msg_chan chan string) {
    var group = 1
    for {
        for i := 1; i <= 10; i++ {
            msg_chan <- strconv.Itoa(group) + ":" + strconv.Itoa(i)
        }
        group++
        time.Sleep(time.Second * 5)
    }
}

func count(msg_chan chan string) {
    for {
        fmt.Println(<-msg_chan)
    }
}

func main() {
    var c = make(chan string, 20)
    go shooting(c)
    go count(c)
    var input string
    fmt.Scanln(&input)
}
相關文章
相關標籤/搜索