go多线程 go语言中不是通过共享内存通信,而是通过通信共享内存
协程goroutine goroutine,即轻量级线程,创建Goroutine的成本很小,它就是一段代码,一个函数入口。以及在堆上为其分配的一个堆栈(初始大小为4K,会随着程序的执行自动增长删除)。因此它非常廉价,Go应用程序可以并发运行数千个Goroutines。
案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package mainimport ( "fmt" "net/http" "time" )func main () { start := time.Now() apis := []string { "https://management.azure.com" , "https://dev.azure.com" , "https://api.github.com" , "https://outlook.office.com/" , "https://api.somewhereintheinternet.com/" , "https://graph.microsoft.com" , } for _, api := range apis { go checkAPI(api) } time.Sleep(3 * time.Second) elapsed := time.Since(start) fmt.Printf("Done! It took %v seconds!\n" , elapsed.Seconds()) }func checkAPI (api string ) { _, err := http.Get(api) if err != nil { fmt.Printf("ERROR: %s is down!\n" , api) return } fmt.Printf("SUCCESS: %s is up and running!\n" , api) }
协程通信channel 使用管道
1 2 3 4 5 6 7 8 9 10 11 12 ch := make (chan int ) ch <- x x = <-ch <-ch close (ch)func send (ch chan <- string ) {} func read (ch <-chan string ) {}
案例1:无缓冲channel
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 package mainimport ( "fmt" "net/http" "time" )func main () { start := time.Now() apis := []string { "https://management.azure.com" , "https://dev.azure.com" , "https://api.github.com" , "https://outlook.office.com/" , "https://api.somewhereintheinternet.com/" , "https://graph.microsoft.com" , } ch := make (chan string ) for _, api := range apis { go checkAPI(api, ch) } for i := 0 ; i < len (apis); i++ { fmt.Print(<-ch) } elapsed := time.Since(start) fmt.Printf("Done! It took %v seconds!\n" , elapsed.Seconds()) }func checkAPI (api string , ch chan string ) { _, err := http.Get(api) if err != nil { ch <- fmt.Sprintf("ERROR: %s is down!\n" , api) return } ch <- fmt.Sprintf("SUCCESS: %s is up and running!\n" , api) }
案例2:有缓冲channel
1 2 3 ch := make (chan string , 10 )
区别
无缓冲的channel在发送数据时,发送者会被阻塞,直到有接收者接收数据。
有缓冲的channel则当缓冲区未满的时候会继续往下执行
多路复用select 语法和switch类似,作用是当case后面的对管道的操作执行成功后,会执行对应的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package mainimport ( "fmt" "time" )func process (ch chan string ) { time.Sleep(3 * time.Second) ch <- "Done processing!" }func replicate (ch chan string ) { time.Sleep(1 * time.Second) ch <- "Done replicating!" }func main () { ch1 := make (chan string ) ch2 := make (chan string ) go process(ch1) go replicate(ch2) for i := 0 ; i < 2 ; i++ { select { case process := <-ch1: fmt.Println(process) case replicate := <-ch2: fmt.Println(replicate) } } }