Go语言 并发编程
作者:Eric 微信:loveoracle11g
1、创建goroutine
// 并行 是两个队列同时使用两台咖啡机 // 并发 是两个队列交替使用一台咖啡机 package main import ( "fmt" "time" ) func newTask() { for { fmt.Println("this is a newTask") time.Sleep(time.Second) // 延时1s } } func main() { go newTask() // 新建一个协程,新建一个任务 for { fmt.Println("this is a main goroutine") time.Sleep(time.Second) // 延时1s } }
2、主goroutine先退出
package main import ( "fmt" "time" ) // 主协程退出了,其它子协程也要跟着退出 func main() { go func() { i := 0 for { i++ fmt.Println("子协程 i =", i) time.Sleep(time.Second) } }() i := 0 for { i++ fmt.Println("main i =", i) time.Sleep(time.Second) if i == 2 { break } } }
3、主协程先退出导致子协程没有来得及调用
package main import ( "fmt" "time" ) func main() { go func() { i := 0 for { i++ fmt.Println("子协程 i =", i) time.Sleep(time.Second) } }() }
4、Gosched的使用
package main import "fmt" func main() { go func() { for i := 0; i < 5; i++ { fmt.Println("Go") } }() for i := 0; i < 2; i++ { fmt.Println("hello") } }
package main import ( "fmt" "runtime" ) func main() { go func() { for i := 0; i < 5; i++ { fmt.Println("Go") } }() for i := 0; i < 2; i++ { // 让出时间片,先让别的协议执行,它执行完毕,再来执行此协程 runtime.Gosched() fmt.Println("hello") } }
5、Goexit的使用
package main import ( "fmt" "runtime" ) func test() { defer fmt.Println("ccccccccccccccccccccccc") // return // 终止此函数 runtime.Goexit() // 终止所在的协程 fmt.Println("ddddddddddddddddddddddddddddd") } func main() { // 创建新建的协程 go func() { fmt.Println("aaaaaaaaaaaaaaaaaaaaaaaaa") // 调用了别的函数 test() fmt.Println("bbbbbbbbbbbbbbbbbbbbbbbbb") }() // 特地写一个死循环,目的不让主协程结束 for { } }
6、GOMAXPROCS的使用
package main import ( "fmt" "runtime" ) func main() { // n := runtime.GOMAXPROCS(1) // 指定以1核运算 n := runtime.GOMAXPROCS(4) // 指定以4核运算 fmt.Println("n =", n) for { go fmt.Print(1) fmt.Print(0) } }
7、多任务资源竞争问题
package main import ( "fmt" "time" ) // 定义一个打印机,参数为字符串,按每个字符打印 // 打印机属于公共资源 func printer(str string) { for _, data := range str { fmt.Printf("%c", data) time.Sleep(time.Second) } fmt.Printf("\n") } func person1() { printer("hello") } func person2() { printer("world") } func main() { // printer("hello") // printer("world") // 新建2个协程,代表2个人,2个人同时使用打印机 go person1() go person2() // 特地不让主协程结束,死循环 for { } }
8、通过channel实现同步
package main import ( "fmt" "time" ) // 全局变量,创建一个channel var ch = make(chan int) // 定义一个打印机,参数为字符串,按每个字符打印 // 打印机属于公共资源 func printer(str string) { for _, data := range str { fmt.Printf("%c", data) time.Sleep(time.Second) } fmt.Printf("\n") } // person1执行完后,才能到person2执行 func person1() { printer("hello") ch <- 666 //给管道写数据,发送 } func person2() { <-ch // 从管道取数据,接收,如果通道没有数据,他就会阻塞 printer("world") } func main() { // printer("hello") // printer("world") // 新建2个协程,代表2个人,2个人同时使用打印机 go person1() go person2() // 特地不让主协程结束,死循环 for { } }
9、通过channel实现同步和数据交互
package main import ( "fmt" "time" ) func main() { // 创建channel ch := make(chan string) defer fmt.Println("主协程也结束了") go func() { defer fmt.Println("子协程调用完毕") for i := 0; i < 2; i++ { fmt.Println("子协程 i =", i) time.Sleep(time.Second) } ch <- "我是子协程,工作完毕" }() str := <-ch // 没有数据前,阻塞 fmt.Println("str =", str) }
10、无缓冲channel
package main import ( "fmt" "time" ) func main() { // 创建channel ch := make(chan int, 0) // len(ch) 缓存区剩余数据个数 // cap(ch) 缓冲区大小 fmt.Printf("len(ch) = %d, cap(ch) = %d\n", len(ch), cap(ch)) // 新建协程 go func() { for i := 0; i < 3; i++ { fmt.Println("子协程:i =", i) ch <- i // 往chan写内容 } }() // 延时 time.Sleep(2 * time.Second) for i := 0; i < 3; i++ { num := <-ch // 读管道中的内容,没有内容前,阻塞 fmt.Println("num =", num) } }
11、