goroutine

 

併發:邏輯上具有同時處理多個任務的能力(單核,上下文切換)c++

並行:物理上同一時刻執行多個併發任務(多核,互不影響)安全

 

package main

import (
	"fmt"
	"time"
)

var c int

func counter() int {
	c++
	return c
}

func main() {
	a := 100
	go func(x, y int) {
		time.Sleep(time.Second) //goroutine在main邏輯以後執行
		fmt.Println("go:", x, y)
	}(a, counter()) //當即計算並賦值
	a += 100
	fmt.Println("main", a, counter())
	time.Sleep(time.Second * 3) //等goroutine結束
}

  

進程退出並不會等併發任務執行結束,可用channel阻塞,而後發出退出信號併發

package main

import (
	"fmt"
	"time"
)

func main() {
	exit := make(chan struct{})
	go func() {
		time.Sleep(time.Second)
		fmt.Println("goroutine done")
		close(exit) //關閉通道,發出信號
	}()
	fmt.Println("main start...")
	<-exit //通道關閉,當即解除阻塞
	fmt.Println("main end...")
}

  

等待多個任務結束,使用sync.WaitGroup,經過設定計數器,讓每一個goroutine在退出前遞減,直至歸零時解除阻塞線程

package main

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

func main() {
	var wg sync.WaitGroup
	for i := 0; i < 10; i++ {
		wg.Add(1) //累加計數

		go func(id int) {
			defer wg.Done() //遞歸計數
			time.Sleep(time.Second)
			fmt.Println("goroutine", id)
		}(i)
	}
	fmt.Println("start")
	wg.Wait() //阻塞,直至計數歸零
	fmt.Println("stop")
}

  

GOMAXPROCSblog

與邏輯核數相等遞歸

package main

import (
	"fmt"
	"math"
	"runtime"
	"sync"
)

func count() {
	x := 0
	for i := 0; i < math.MaxUint32; i++ {
		x += i
	}
	fmt.Println(x)
}

func test(n int) {
	for i := 0; i < n; i++ {
		count()
	}
}

func test2(n int) {
	var wg sync.WaitGroup
	wg.Add(n)
	for i := 0; i < n; i++ {
		go func() {
			count()
			wg.Done()
		}()
	}
	wg.Wait()
}

func main() {
	n := runtime.GOMAXPROCS(0)
	test2(n)
}

  

可在多處使用Wait阻塞,它們都能收到通知進程

package main

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

func main() {
	var wg sync.WaitGroup
	wg.Add(1)

	go func() {
		wg.Wait()
		fmt.Println("wait exit")
	}()

	go func() {
		time.Sleep(time.Second)
		fmt.Println("done")
		wg.Done()
	}()
	wg.Wait()
	fmt.Println("main exit")
}

 

多個goroutine進行通訊

方式一:全局變量(加鎖)

package main

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

var (
	m    = make(map[int]int)
	lock sync.Mutex
)

type task struct {
	n int
}

func calc(t *task) {
	sum := 1
	for i := 1; i <= t.n; i++ {
		sum *= i
	}
	lock.Lock()
	m[t.n] = sum
	lock.Unlock()
}

func main() {
	for i := 1; i < 10; i++ {
		t := &task{n: i}
		go calc(t)
	}
	time.Sleep(time.Second * 2)

	lock.Lock()
	for k, v := range m {
		fmt.Printf("%d! is %v\n", k, v)
	}
	lock.Unlock()
}

  

用到goroutine時編譯加-race競爭檢測ip

方式二:channel 

channel概念

  • 相似pipe
  • 先進先出
  • 線程安全,多個goroutine同時訪問,不須要加鎖
  • channel是有類型的,一個整數的channel只能存放整數

channel申明

  • var 變量名 chan 類型
  • var test chan int
  • var test chan map[string]string

 

channel關閉string

方法一:v,ok := <-chanit

package main

import (
	"fmt"
)

func main() {
	ch := make(chan int, 10)
	for i := 0; i < 10; i++ {
		ch <- i
	}
	close(ch)
	for {
		b, ok := <-ch
		if ok == false {
			break
		}
		fmt.Println(b)
	}
}

  

方式二:

for v := range chan

channel讀寫

package main

import (
	"fmt"
	"time"
)

func write(ch chan int) {
	for i := 0; i < 100; i++ {
		ch <- i
	}
}

func read(ch chan int) {
	var a int
	for {
		a = <-ch
		fmt.Println("read", a)
	}

}

func main() {
	intChan := make(chan int, 10)
	go write(intChan)
	go read(intChan)
	time.Sleep(time.Second)
}

  

判斷10000內的素數

package main

import (
	"fmt"
)

func calc(taskChan chan int, resChan chan int, exitChan chan bool) {
	for v := range taskChan {
		flag := true
		for i := 2; i < v; i++ {
			if v%i == 0 {
				flag = false
				break
			}
		}
		if flag {
			resChan <- v
		}
	}
	exitChan <- true
}

func main() {
	taskChan := make(chan int, 1000)
	resChan := make(chan int, 1000)
	exitChan := make(chan bool, 8)

	go func() {
		for i := 1; i < 10000; i++ {
			taskChan <- i
		}
		close(taskChan)
	}()

	for i := 0; i < 8; i++ {
		go calc(taskChan, resChan, exitChan)
	}

	go func() {
		for i := 0; i < 8; i++ {
			<-exitChan
		}
		close(resChan)
	}()

	for v := range resChan {
		fmt.Println(v)
	}
}

  

定時器

package main

import (
	"fmt"
	"time"
)

func main() {
	t := time.NewTicker(time.Second)
	for v := range t.C {
		fmt.Println("hello", v)
	}
t.Stop() }

  

  

超時控制

package main

import (
	"fmt"
	"time"
)

func main() {
	select {
	case <-time.After(time.Second):
		fmt.Println("timeout")
	}
}
相關文章
相關標籤/搜索