Go併發模式代碼示例

演講稿:Go Concurrency Patternsgolang

Youtube視頻web

做者:Rob Pikeshell

練習題目:谷歌搜索:一個虛擬框架服務器

谷歌搜索1.0

PPT從43頁開始:https://talks.golang.org/2012/concurrency.slide#43app

Google函數接受一個查詢並返回一個結果切片(只是字符串)。Google連續調用網頁、圖片和視頻搜索,並將它們附加到搜索結果切片中。框架

代碼以下:ide

package main

import (
    "fmt"
    "math/rand"
    "time"
)

var (
    Web   = fakeSearch("web")
    Image = fakeSearch("image")
    Video = fakeSearch("video")
)

type Result string

type Search func(query string) Result

func fakeSearch(kind string) Search {
    return func(query string) Result {
        time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
        return Result(fmt.Sprintf("%s result for %q\n", kind, query))
    }
}

func Google(query string) (results []Result) {
    results = append(results, Web(query))
    results = append(results, Image(query))
    results = append(results, Video(query))
    return
}

func main() {
    rand.Seed(time.Now().UnixNano())
    start := time.Now()
    results := Google("golang")
    elapsed := time.Since(start)
    fmt.Println(results)
    fmt.Println(elapsed)
}

運行結果以下:函數

[web result for "golang"
 image result for "golang"
 video result for "golang"
]
153.365484ms


谷歌搜索2.0

同時運行網頁、圖像和視頻搜索,並等待全部結果。沒有鎖,沒有條件變量,沒有回調。code

代碼以下,關注Google函數。視頻

package main

import (
    "fmt"
    "math/rand"
    "time"
)

var (
    Web   = fakeSearch("web")
    Image = fakeSearch("image")
    Video = fakeSearch("video")
)

type Result string

type Search func(query string) Result

func fakeSearch(kind string) Search {
    return func(query string) Result {
        time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
        return Result(fmt.Sprintf("%s result for %q\n", kind, query))
    }
}

func Google(query string) (results []Result) {
    c := make(chan Result)
    go func() { c <- Web(query) } ()
    go func() { c <- Image(query) } ()
    go func() { c <- Video(query) } ()

    for i := 0; i < 3; i++ {
        result := <-c
        results = append(results, result)
    }
    return
}

func main() {
    rand.Seed(time.Now().UnixNano())
    start := time.Now()
    results := Google("golang")
    elapsed := time.Since(start)
    fmt.Println(results)
    fmt.Println(elapsed)
}


谷歌搜索2.1

不要等待緩慢的服務器。沒有鎖,無條件變量,沒有回調。經過select的超時實現,須要把time.After定義的超時通道放在for循環外層。

package main

import (
    "fmt"
    "math/rand"
    "time"
)

var (
    Web   = fakeSearch("web")
    Image = fakeSearch("image")
    Video = fakeSearch("video")
)

type Result string

type Search func(query string) Result

func fakeSearch(kind string) Search {
    return func(query string) Result {
        time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
        return Result(fmt.Sprintf("%s result for %q\n", kind, query))
    }
}

func Google(query string) (results []Result) {
    c := make(chan Result)
    go func() { c <- Web(query) } ()
    go func() { c <- Image(query) } ()
    go func() { c <- Video(query) } ()

    timeout := time.After(80 * time.Millisecond)
    for i := 0; i < 3; i++ {
        select {
        case result := <-c:
            results = append(results, result)
        case <-timeout:
            fmt.Println("timed out")
            return
        }
    }
    return
}

func main() {
    rand.Seed(time.Now().UnixNano())
    start := time.Now()
    results := Google("golang")
    elapsed := time.Since(start)
    fmt.Println(results)
    fmt.Println(elapsed)
}


谷歌搜索3.0

內容從48頁到51頁。

使用複製的搜索服務器減小尾部延遲。一樣沒有鎖,沒有條件變量,沒有回調。

問:咱們如何避免由於服務器運行緩慢而丟棄結果?

答: 複製服務器。 向多個副本發送請求,並使用第一個響應。

代碼以下:

package main

import (
    "fmt"
    "math/rand"
    "time"
)

var (
    Web1   = fakeSearch("web")
    Web2   = fakeSearch("web")
    Image1 = fakeSearch("image")
    Image2 = fakeSearch("image")
    Video1 = fakeSearch("video")
    Video2 = fakeSearch("video")
)

type Result string

type Search func(query string) Result

func fakeSearch(kind string) Search {
    return func(query string) Result {
        time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
        return Result(fmt.Sprintf("%s result for %q\n", kind, query))
    }
}

func Google(query string) (results []Result) {
    c := make(chan Result)
    go func() { c <- First(query, Web1, Web2) } ()
    go func() { c <- First(query, Image1, Image2) } ()
    go func() { c <- First(query, Video1, Video2) } ()
    timeout := time.After(80 * time.Millisecond)
    for i := 0; i < 3; i++ {
        select {
        case result := <-c:
            results = append(results, result)
        case <-timeout:
            fmt.Println("timed out")
            return
        }
    }
    return
}

func First(query string, replicas ...Search) Result {
    c := make(chan Result)
    searchReplica := func(i int) { c <- replicas[i](query) }
    for i := range replicas {
        go searchReplica(i)
    }
    return <-c
}

func main() {
    rand.Seed(time.Now().UnixNano())
    start := time.Now()
    results := Google("golang")
    elapsed := time.Since(start)
    fmt.Println(results)
    fmt.Println(elapsed)
}

執行結果以下:

[image result for "golang"
 web result for "golang"
 video result for "golang"
]
53.605273ms
相關文章
相關標籤/搜索