Go:並行性

基本

  1. スレッドとは何ですか?
    スレッドは、プロセス内の実行パスです。
  2. なぜマルチスレッドなのか?
    アイデアは、プロセスを複数のスレッドに分割することによって並列処理を実現することです。たとえば、ブラウザでは、複数のタブを異なるスレッドにすることができます。
  3. プロセスとスレッド
    主な違いは、同じプロセス内のスレッドは共有メモリスペースで実行されるのに対し、プロセスは別々のメモリスペースで実行されることです。

Goroutine

Agoroutineは、Goランタイムによって管理される軽量スレッドです。

go f(x, y, z) // starts a new goroutine by running f(x, y, z)

評価のはfxyz現在のゴルーチンとで起こる実行f新しいゴルーチンで起こります。

ゴルーチンは同じアドレス空間で実行されるため、共有メモリへのアクセスを同期する必要があります。sync他のプリミティブがあるとして、あなたが行くには非常にそれらを必要としませんが、パッケージには、便利なプリミティブを提供します。

  1. ケース1
func display(str string) {
    
     
	time.Sleep(2 * time.Second) 
	fmt.Println(str) 
}
func main() {
    
     
	display("NORMAL")
	go display("GOROUTINE")
}

出力:NORMAL
2。ケース2

func display(str string) {
    
     
	time.Sleep(2 * time.Second) 
	fmt.Println(str) 
}
func main() {
    
     
	go display("GOROUTINE")
	display("NORMAL")
}

出力:GOROUTINE\nNORMAL
3。ケース3

func display(str string) {
    
    
	fmt.Println(str) 
}
func main() {
    
     
	go display("GOROUTINE")
	display("NORMAL")
}

出力: NORMAL

チャンネル

チャネルは、チャネルオペレータと送受信できる型付きコンジットです<-

ch <- v // send v to channel ch
v := <- ch // receive from ch, and assign value to v

// like map and slice, channel must be created before use
ch := make(chan int)

1つのタスクを一緒に解決する2つのゴルーチンの例:

func sum(s []int, c chan int) {
    
    
	sum := 0
	for _, v := range s {
    
    
		sum += v
	}
	c <- sum // send sum to 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 // receive from c

	fmt.Println(x, y, x+y)
}

バッファリングされたチャネル

チャネルはバッファリングできます
バッファリングされたmakeチャネルを初期化するための2番目の引数としてバッファ長を指定します。

ch := make(chan int, 100)

バッファがいっぱいの場合にのみ、バッファされたチャネルブロックに送信します。バッファが空のときにブロックを受け取ります。

func main() {
    
    
	ch := make(chan int, 2)
	ch <- 1
	ch <- 2
	ch <- 3 // deadlock, all goroutines are asleep
	fmt.Println(<-ch)
	fmt.Println(<-ch)
}

範囲と閉じる

送信者はチャネルを閉じることができます。

ch := make(chan int, 2)
ch <- 1
ch <- 2
close(ch)

受信者は、チャネルが閉じているかどうかをテストできます。

v, ok := <-ch

ループfor i := range chは、チャネルchが閉じるまでチャネルから値を繰り返し受け取ります
閉じたチャネルで送信すると、が発生しpanicます。
チャネルはファイルとは異なります。通常、それらを閉じる必要はありません。rangeループを終了するなど、これ以上値が来ないことを受信者に通知する必要がある場合にのみ、閉じる必要があります。

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ステートメントにより、ゴルーチンは複数の通信操作(c <-xなど)を待機します。ブロックを実行することができ、その例1まで、それはそのケースを実行します。複数の準備ができている場合は、ランダムに1つを選択します。
select

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)
}

匿名のゴルーチン関数の構文:

go func() {
    
    
	// function body
}()

defaultaケースは、select他のケースの準備ができていない場合に実行されます。

sync.Mutex

// SafeCounter is safe to use concurrently.
type SafeCounter struct {
    
    
	mu sync.Mutex // make sure only one goroutine can access a variable at a time to avoid conflicts
	v  map[string]int
}

// Inc increments the counter for the given key.
func (c *SafeCounter) Inc(key string) {
    
    
	// define a block of code to be executed in mutual exclusion by surrounding it with a call to Lock and Unlock
	c.mu.Lock()
	// Lock so only one goroutine at a time can access the map c.v.
	c.v[key]++
	c.mu.Unlock()
}

// Value returns the current value of the counter for the given key.
func (c *SafeCounter) Value(key string) int {
    
    
	c.mu.Lock()
	// Lock so only one goroutine at a time can access the map c.v.
	defer c.mu.Unlock() // use defer to ensure the mutex will be unlocked
	return c.v[key]
}

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

おすすめ

転載: blog.csdn.net/Hita999/article/details/112614638