併發:邏輯上具有同時處理多個任務的能力(單核,上下文切換)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") }
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關閉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") } }