_同時言語を行きます

同時
コア言語の一部として同時構造を移動します。このセクションでは、コースのいくつかの例を説明し、その使用を実証しました。

行く-ZHグループ翻訳、執筆者のグループを作成します。
https://tour.go-zh.org/concurrency/1

  • Go 程

ゴーチェン(ゴルーチン)はゴーラン軽量スレッドによって管理されています。

go f(x, y, z)

私たちは、新しいプロセスを開始し、Goを実行します

f(x, y, z)

fxyそしてz、評価ゴーの現在のプロセスで発生し、f実行が新しい囲碁プロセスで行われます。

共有メモリにアクセスするときと同じアドレス空間で実行を離れて行く、それを同期させる必要があります。[[ Https://go-zh.org/pkg/sync/ ] [ sync]]パッケージには、この機能を提供しますが、他の方法は、(次ページ参照)があるので、それは多くの場合、移動に使用されていません。

// +build OMIT

package main

import (
    "fmt"
    "time"
)

func say(s string) {
    for i := 0; i < 5; i++ {
        time.Sleep(100 * time.Millisecond)
        fmt.Println(s)
    }
}

func main() {
    go say("world")
    say("hello")
}
  • 信道

チャンネルには、オペレータがそこを通ってチャンネルを使用することができ、型のパイプで<-送信または値を受信されます。

ch <- v    // 将 v 发送至信道 ch。
v := <-ch  // 从 ch 接收值并赋予 v。

(「矢印」は、データフローの方向です。)

そして、チャンネルのようなマップとセクションでは、使用する前に作成する必要があります。

ch := make(chan int)

もう一方の端の準備ができるまで、デフォルトでは、送信および受信操作がブロックされています。このプロセスは、明示的なロック変数やレース条件なしで行くように同期させることができます。

セクションの数を合計する次の例では、2ゴーを処理するためにタスクを割り当てます。プロセスが自分の行く2つの計算を完了したら、それは最終結果から計算することができます。

// +build OMIT

package main

import "fmt"

func sum(s []int, c chan int) {
    sum := 0
    for _, v := range s {
        sum += v
    }
    c <- sum // 将和送入 c
}

func main() {
    s := []int{7, 2, 8, -9, 4, 0}

    c := make(chan int)
    go sum(s[:len(s)/2], c)
    go sum(s[len(s)/2:], c)
    x, y := <-c, <-c // 从 c 中接收

    fmt.Println(x, y, x+y)
}
  • チャンネルバッファ

チャネルができるバッファリング設けられた第二のパラメータとして、バッファの長makeチャネルバッファがで初期化されます。

ch := make(chan int, 100)

チャネル・バッファが一杯になったときにのみ、データは閉塞それ送信されます。バッファが空の場合、受信者はブロックされます。

バッファを埋めるために、サンプルを変更し、何が起こるかを参照してください。

// +build OMIT

package main

import "fmt"

func main() {
    ch := make(chan int, 2)
    ch <- 1
    ch <- 2
    fmt.Println(<-ch)
    fmt.Println(<-ch)
}
  • 範囲の和の近く

送信者ができcloseつのチャネルをオフにする必要がないことを示す値に送信します。その後、実行、値がない場合に受信することができ、チャネルが閉じられた:受信者は、チャネルが二番目の引数を受信するために割り当てられた式によって閉鎖されているかどうかを試験することができます

v, ok := <-ch

この時点で、okそれが設定されますfalse

巡回for:=の範囲はc、それが閉じられるまで常に、チャネルから値を受け取ります。

注意:送信者だけがチャネルを閉じることができ、および受信機はできません。パニック(パニック)が発生するプログラムを閉じられているチャネルにデータを送信します。

また、注意してください:異なるチャンネルやファイル、通常はそれらを閉鎖することなく。それは受信者に伝える必要がある場合にのみ、もはや値だけなの終端として、閉じる必要が送信する必要がありませんrangeサイクル。

// +build OMIT

package main

import (
    "fmt"
)

func fibonacci(n int, c chan int) {
    x, y := 0, 1
    for i := 0; i < n; i++ {
        c <- x
        x, y = y, x+y
    }
    close(c)
}

func main() {
    c := make(chan int, 10)
    go fibonacci(cap(c), c)
    for i := range c {
        fmt.Println(i)
    }
}
  • select文

select 文のプロセスが通信複数の動作を待つことができる作るために移動します。

selectそれはブランチを実行しますその時点で、実行し続けることができ枝に詰まらせます。複数のブランチの準備が整ったら、ランダムに実行を選択します。

// +build OMIT

package main

import "fmt"

func fibonacci(c, quit chan int) {
    x, y := 0, 1
    for {
        select {
        case c <- x:
            x, y = y, x+y
        case <-quit:
            fmt.Println("quit")
            return
        }
    }
}

func main() {
    c := make(chan int)
    quit := make(chan int)
    go func() {
        for i := 0; i < 10; i++ {
            fmt.Println(<-c)
        }
        quit <- 0
    }()
    fibonacci(c, quit)
}
  • デフォルトの選択

場合はselect、他の支店での時間は準備ができていない、defaultブランチが実行されます。

使用して、送信または受信しようとしたときに詰まらないようにするために発生したdefault枝を:

select {
case i := <-c:
    // 使用 i
default:
    // 从 c 中接收会阻塞时执行
}
// +build OMIT

package main

import (
    "fmt"
    "time"
)

func main() {
    tick := time.Tick(100 * time.Millisecond)
    boom := time.After(500 * time.Millisecond)
    for {
        select {
        case <-tick:
            fmt.Println("tick.")
        case <-boom:
            fmt.Println("BOOM!")
            return
        default:
            fmt.Println("    .")
            time.Sleep(50 * time.Millisecond)
        }
    }
}
  • 演習:同等のバイナリ検索ツリー

値の同じシーケンスは、バイナリツリーの異なるリーフノードに格納することができます。例えば、2進木の以下のシーケンスが保存されます1,1,2,3,5,8,13

.image /content/img/tree.png

ほとんどの言語では、関数の同じシーケンスを保存するには、2つのバイナリツリーが非常に複雑であるかどうかを確認します。
私たちは、シンプルなソリューションを書くために行くの並行性とチャネルを使用します。

この実施形態は、使用treeタイプを定義するパッケージを、。

type Tree struct {
    Left  *Tree
    Value int
    Right *Tree
}

[[クリック:クリックしてJavaScriptを継続する( '.next-ページ')] [次のページ]]を。

  • 演習:同等のバイナリ検索ツリー

1.実装Walkの機能を。

2.テストWalk機能。

機能がされてtree.New(k)二分探索木をソートランダム構造を構築するために使用される、それはの値を保持k2k3k、...、を10k

新しいチャネルを作成chし、そのステッパーを:

go Walk(tree.New(1), ch)

次いで10とプリントチャネルから値を読み出します。それは数でなければなりません1,2、3,...、 10

3.使用Walk達成するためにSame検出する機能をt1し、t2同じ値を格納するかどうか。

4.テストSame機能。

Same(tree.New(1),tree.New(1))应当返回をtrueに,而同じ、(tree.New(1)、tree.New(2))返されるべきfalse

Tree文書が上で利用可能な[[ https://godoc.org/golang.org/x/tour/tree#Tree ] [ここ]]を発見しました。

// +build no-build OMIT

package main

import "golang.org/x/tour/tree"

// Walk 步进 tree t 将所有的值从 tree 发送到 channel ch。
func Walk(t *tree.Tree, ch chan int)

// Same 检测树 t1 和 t2 是否含有相同的值。
func Same(t1, t2 *tree.Tree) bool

func main() {
}
  • sync.Mutex

私たちは離れて、様々な移動の間の通信のために非常に適したチャネルを見てきました。

しかし、我々はそれを通信する必要がない場合は?私たちはただ一つのプロセスだけがアクセスできるようにしたい場合は、競合を回避するために、例えば、共有変数を行きますか?

ここに関連する概念は呼ばれているミューテックス(相互排他)*、我々は通常使用ミューテックス(ミューテックス)のようなメカニズムを提供するために、データ構造を。

ゴー[[標準ライブラリの提供https://go-zh.org/pkg/sync/#Mutex ] [ sync.Mutex]]とmutex型の2つのメソッドを:

  • Lock
  • Unlock

私たちは前にコードを呼び出すことができるLockコードが呼び出した後、方法Unlock相互排除のコードの実装を確実にするための方法を。参照Inc方法を。

また、使用することができますdeferミューテックスのロックが解除されることを確認する声明を。参照Value方法を。

// +build OMIT

package main

import (
    "fmt"
    "sync"
    "time"
)

// SafeCounter 的并发使用是安全的。
type SafeCounter struct {
    v   map[string]int
    mux sync.Mutex
}

// Inc 增加给定 key 的计数器的值。
func (c *SafeCounter) Inc(key string) {
    c.mux.Lock()
    // Lock 之后同一时刻只有一个 goroutine 能访问 c.v
    c.v[key]++
    c.mux.Unlock()
}

// Value 返回给定 key 的计数器的当前值。
func (c *SafeCounter) Value(key string) int {
    c.mux.Lock()
    // Lock 之后同一时刻只有一个 goroutine 能访问 c.v
    defer c.mux.Unlock()
    return c.v[key]
}

func main() {
    c := SafeCounter{v: make(map[string]int)}
    for i := 0; i < 1000; i++ {
        go c.Inc("somekey")
    }

    time.Sleep(time.Second)
    fmt.Println(c.Value("somekey"))
}
  • 演習:Webクローラー

この演習では、Webクローラーを並列化するために行くの同時実行機能を使用します。

変更Crawl機能パラレルグラブURLを、そして繰り返されないことが保証。

ヒント:あなたは、すでに取得したURLをキャッシュするためにマップを使用しますが、マップ自体がセキュリティによって複雑にされていないように注意することができます!

// +build OMIT

package main

import (
    "fmt"
)

type Fetcher interface {
    // Fetch 返回 URL 的 body 内容,并且将在这个页面上找到的 URL 放到一个 slice 中。
    Fetch(url string) (body string, urls []string, err error)
}

// Crawl 使用 fetcher 从某个 URL 开始递归的爬取页面,直到达到最大深度。
func Crawl(url string, depth int, fetcher Fetcher) {
    // TODO: 并行的抓取 URL。
    // TODO: 不重复抓取页面。
        // 下面并没有实现上面两种情况:
    if depth <= 0 {
        return
    }
    body, urls, err := fetcher.Fetch(url)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Printf("found: %s %q\n", url, body)
    for _, u := range urls {
        Crawl(u, depth-1, fetcher)
    }
    return
}

func main() {
    Crawl("https://golang.org/", 4, fetcher)
}

// fakeFetcher 是返回若干结果的 Fetcher。
type fakeFetcher map[string]*fakeResult

type fakeResult struct {
    body string
    urls []string
}

func (f fakeFetcher) Fetch(url string) (string, []string, error) {
    if res, ok := f[url]; ok {
        return res.body, res.urls, nil
    }
    return "", nil, fmt.Errorf("not found: %s", url)
}

// fetcher 是填充后的 fakeFetcher。
var fetcher = fakeFetcher{
    "https://golang.org/": &fakeResult{
        "The Go Programming Language",
        []string{
            "https://golang.org/pkg/",
            "https://golang.org/cmd/",
        },
    },
    "https://golang.org/pkg/": &fakeResult{
        "Packages",
        []string{
            "https://golang.org/",
            "https://golang.org/cmd/",
            "https://golang.org/pkg/fmt/",
            "https://golang.org/pkg/os/",
        },
    },
    "https://golang.org/pkg/fmt/": &fakeResult{
        "Package fmt",
        []string{
            "https://golang.org/",
            "https://golang.org/pkg/",
        },
    },
    "https://golang.org/pkg/os/": &fakeResult{
        "Package os",
        []string{
            "https://golang.org/",
            "https://golang.org/pkg/",
        },
    },
}
  • どこ次の?

[[戻るhttps://go-zh.org/doc/ ] [ドキュメント]]は素晴らしいスタートです。
これは、リファレンスガイド、ビデオ、より多くの情報が含まれています。

囲碁コードを整理する方法を学習し、それに取り組んで、[参照https://www.youtube.com/watch?v=XCsL89YtqCs [] [このビデオを]]、または読み取り[ https://go-zh.org/ DOC / code.html ] [ゴーコード]]を作成する方法。

あなたは、標準ライブラリの助けが必要な場合は、[[を参照してくださいhttps://go-zh.org/pkg/ ] [パッケージマニュアル]]。それ自体が助け言語である場合は、[[読み取りhttps://go-zh.org/ref/spec ] [言語仕様]]は楽しいものです。

さらに、同時実行モデルを探る見に行く[https://www.youtube.com/watch?v=f6kdp27TYZs][Go同時実行モデルを][https://www.youtube.com/watch?v=QDDwwePbDtw] [深さ同時実行モデルを移動]と[[読み取りhttps://go-zh.org/doc/codewalk/sharemem/ ] [共有メモリ通信を介し]コード旅。

、Webアプリケーションを書き始める見てみたい[https://vimeo.com/53221558] [簡単なプログラミング環境を]と[[読み取りhttps://go-zh.org/doc/articles/wiki/ ] [書き込みWebアプリケーション]]ガイド。

[[ Https://go-zh.org/doc/codewalk/functions/ ] [機能:第一級オブジェクトを移動します]]は、興味深い機能の種類を示しています。

[[ Https://blog.go-zh.org/ ] []のブログに移動します]ゴーの上の多数の記事や情報を持っています。

[[ Https://www.mikespook.com/tag/golang/ ] [mikespookのブログ]]ゴーの上、中国と翻訳された記事が多数あります。

オープンソースの電子書籍[[ https://github.com/astaxie/build-web-application-with-golang ] [移動ウェブ]プログラミング]と[[ https://github.com/Unknwon/the-way-to- go_ZH_CN ] [戻るガイド]あなたはより深い理解を習得し、言語を行くことができますはじめに。

[[訪問https://go-zh.org ] [go-zh.org]]の詳細を学ぶために。

おすすめ

転載: www.cnblogs.com/pdev/p/10936485.html
おすすめ