- package main
-
- //使用协程
- import (
- "fmt"
- "strconv"
- "time"
- )
-
- func test() {
- for i := 1; i <= 10; i++ {
- fmt.Println("test() hello world" + strconv.Itoa(i))
- time.Sleep(time.Second)
- }
- }
-
- // 主线程和test协程同时运行
- func main() {
- go test() //开启了一个协程
- for i := 1; i <= 10; i++ {
- //strconv.Itoa函数:将整型转换为字符串
- fmt.Println("main() hello Golang" + strconv.Itoa(i))
- time.Sleep(time.Second)
- }
- }
- main() hello Golang1
- test() hello world1
- main() hello Golang2
- test() hello world2
- test() hello world3
- main() hello Golang3
- main() hello Golang4
- test() hello world4
- test() hello world5
- main() hello Golang5
- main() hello Golang6
- test() hello world6
- test() hello world7
- main() hello Golang7
- main() hello Golang8
- test() hello world8
- test() hello world9
- main() hello Golang9
- main() hello Golang10
- test() hello world10
- package main
-
- import (
- "fmt"
- "sync"
- "time"
- )
-
- //计算1-20的各个数的阶乘,并且把各个数的阶乘放入到map中
- //最后显示出来,要求使用goroutine完成
-
- //思路:1.编写一个函数,计算各个数的阶乘,并放入到map中
- //2.我们启动的协程多个,统计的结果放入到map中
- //3.map应该做出一个全局变量
-
- var (
- myMap = make(map[int]int, 20)
- //lock是一个全局的互斥锁
- //Mutex:互斥
- lock sync.Mutex
- )
-
- func test(n int) {
- res := 1
- for i := 1; i <= n; i++ {
- res *= i
- }
- //把结果放入到map中
- //concurrent map writes
- //加锁
- lock.Lock()
- myMap[n] = res
- lock.Unlock()
- }
-
- func main() {
-
- //开启多个协程完成这个任务
- for i := 1; i <= 20; i++ {
- go test(i)
- }
-
- //让主线程休眠,因为主线程执行完后,协程就会中止
- time.Sleep(time.Second * 5)
-
- //输出结果,遍历这个结果
- //lock.Lock()
- for i, v := range myMap {
- fmt.Printf("map[%d]=%d\n", i, v)
- }
- //lock.Unlock()
- }
- map[3]=6
- map[7]=5040
- map[10]=3628800
- map[11]=39916800
- map[19]=121645100408832000
- map[20]=2432902008176640000
- map[13]=6227020800
- map[9]=362880
- map[16]=20922789888000
- map[4]=24
- map[5]=120
- map[6]=720
- map[8]=40320
- map[15]=1307674368000
- map[18]=6402373705728000
- map[17]=355687428096000
- map[14]=87178291200
- map[1]=1
- map[2]=2
- map[12]=479001600
(1).Channel中只能存放指定的数据类型
(2).Channel数据放满后,就不能放入了
(3).如果从Channel中取出数据后,可以继续放入
(4).在没有使用协程的情况下,如果Channel数据取完了,再取,就会报dead lock
- package main
-
- import "fmt"
-
- /**
- Channel使用注意事项
- 1.Channel中只能存放指定的数据类型
- 2.Channel数据放满后,就不能放入了
- 3.如果从Channel中取出数据后,可以继续放入
- 4.在没有使用协程的情况下,如果Channel数据取完了,再取,就会报dead lock
- */
- //演示管道需求
- //channel相当于queue
-
- func main() {
- //1.创建一个存放3个int类型的管道
- var intChan chan int
- //capacity=3
- intChan = make(chan int, 3)
-
- //向管道写入数据
- intChan <- 10
- num := 211
- intChan <- num
-
- //4.看看管道的长度和容量
- fmt.Printf("channel len=%v cap=%v \n", len(intChan), cap(intChan))
-
- //5.从管道中读取数据
- var num2 int
- num2 = <-intChan
- fmt.Println("num2=", num2)
- fmt.Printf("channel len=%v cap=%v \n", len(intChan), cap(intChan))
- }
- channel len=2 cap=3
- num2= 10
- channel len=1 cap=3
- package main
-
- import "fmt"
-
- // 1.关闭管道,管道不能被写入数据,但是可以取出数据
- func test1() {
- intChan := make(chan int, 3)
- intChan <- 100
- intChan <- 200
- close(intChan)
- intChan <- 300
- fmt.Println("Hello")
-
- }
-
- // 遍历管道
- func test2() {
- intChan := make(chan int, 100)
- for i := 0; i < 100; i++ {
- intChan <- i * 2
- }
- //这个方法的前提是Channel要关闭,否则出现deadlock
- close(intChan)
- for v := range intChan {
- fmt.Println("v=", v)
- }
- }
-
- func main() {
- test2()
- }
- package main
-
- import (
- "fmt"
- "time"
- )
-
- /*
- *
- goroutine和channel协同工作案例
- 1.开启一个writeData协程,向管道intChan输入50个整数
- 2.开启一个readData协程,从管道intChan中读取writeData写入数据
- 3.writeData和readData操作的都是同一条管道
- 4.主线程需要等待writeData和readData协程都完成工作才退出
- */
- func writeData(intChan chan int) {
- for i := 1; i <= 50; i++ {
- intChan <- i
- time.Sleep(time.Second)
- fmt.Println("writeData=", i)
- }
- close(intChan)
- }
- func readData(intChan chan int, exitChan chan bool) {
- for {
- v, ok := <-intChan
- if !ok {
- break
- }
- time.Sleep(time.Second)
- fmt.Println("readData=", v)
- }
- //读完数据后
- exitChan <- true
- close(exitChan)
- }
- func main() {
- intChan := make(chan int, 50)
- exitChan := make(chan bool, 1)
- go writeData(intChan)
- go readData(intChan, exitChan)
-
- //time.Sleep(time.Second * 10)
- for {
- _, ok := <-exitChan
- if ok {
- break
- }
- }
- }
- writeData= 1
- readData= 1
- readData= 2
- writeData= 2
- readData= 3
- writeData= 3
- readData= 4
- writeData= 4
- readData= 5
- writeData= 5
- readData= 6
- writeData= 6
- readData= 7
- writeData= 7
- readData= 8
- writeData= 8
- readData= 9
- writeData= 9
- readData= 10
- writeData= 10
- readData= 11
- writeData= 11
- readData= 12
- writeData= 12
- readData= 13
- writeData= 13
- readData= 14
- writeData= 14
- readData= 15
- writeData= 15
- readData= 16
- writeData= 16
- readData= 17
- writeData= 17
- readData= 18
- writeData= 18
- readData= 19
- writeData= 19
- readData= 20
- writeData= 20
- readData= 21
- writeData= 21
- readData= 22
- writeData= 22
- readData= 23
- writeData= 23
- readData= 24
- writeData= 24
- readData= 25
- writeData= 25
- readData= 26
- writeData= 26
- readData= 27
- writeData= 27
- readData= 28
- writeData= 28
- readData= 29
- writeData= 29
- readData= 30
- writeData= 30
- readData= 31
- writeData= 31
- readData= 32
- writeData= 32
- readData= 33
- writeData= 33
- readData= 34
- writeData= 34
- readData= 35
- writeData= 35
- readData= 36
- writeData= 36
- readData= 37
- writeData= 37
- readData= 38
- writeData= 38
- readData= 39
- writeData= 39
- readData= 40
- writeData= 40
- readData= 41
- writeData= 41
- readData= 42
- writeData= 42
- readData= 43
- writeData= 43
- readData= 44
- writeData= 44
- readData= 45
- writeData= 45
- readData= 46
- writeData= 46
- readData= 47
- writeData= 47
- readData= 48
- writeData= 48
- readData= 49
- writeData= 49
- readData= 50
- writeData= 50
- package main
-
- import (
- "fmt"
- "time"
- )
-
- //协程求素数
- //要求统计1-200的数字中,哪些是素数?
-
- // 使用并行的方式,将统计素数的任务分配给多个(4个)goroutine去完成
- func putNum(intChan chan int) {
- for i := 1; i <= 200; i++ {
- intChan <- i
- }
- //关闭
- close(intChan)
- }
-
- // 从intChan取出数据,判断是否为素数,如果是,就放入到primeChan
- func primeNum(intChan chan int, primeChan chan int, exitChan chan bool) {
-
- for {
- num, ok := <-intChan
- if !ok {
- break
- }
- flag := true
- for i := 2; i < num; i++ {
- if num%i == 0 {
- flag = false
- break
- }
- }
- if flag {
- //放入素数管道
- primeChan <- num
- }
- }
- fmt.Println("有一个primeNum协程因为取不到数据,退出")
- //这里我们还不能关闭primeChan
- //向exitChan写入true
- exitChan <- true
- }
-
- func main() {
- intChan := make(chan int, 1000)
- //放入结果
- primeChan := make(chan int, 10000)
-
- //标识退出的管道
- exitChan := make(chan bool, 4)
-
- start := time.Now().Unix()
- //开启一个协程,向intChan放入1-8000个数
- go putNum(intChan)
-
- //开启4个协程向intChan取出数据并判断是否为素数
- //如果是素数直接放入primeChan
- for i := 0; i < 4; i++ {
- go primeNum(intChan, primeChan, exitChan)
- }
-
- go func() {
- //这里主线程要进行处理
- for i := 0; i < 4; i++ {
- <-exitChan
- }
- //从exitChan取出了4个结果,可以放心的关闭primeChan
- end := time.Now().Unix()
- fmt.Println("使用协程耗时=", end-start)
- close(primeChan)
- }()
-
- //遍历primeNum,把结果取出
- for {
- res, ok := <-primeChan
- if !ok {
- break
- }
- fmt.Printf("素数=%d\n", res)
- }
- fmt.Println("main()退出")
- }
- 素数=1
- 素数=2
- 有一个primeNum协程因为取不到数据,退出
- 有一个primeNum协程因为取不到数据,退出
- 有一个primeNum协程因为取不到数据,退出
- 素数=3
- 有一个primeNum协程因为取不到数据,退出
- 使用协程耗时= 0
- 素数=5
- 素数=7
- 素数=11
- 素数=13
- 素数=17
- 素数=19
- 素数=23
- 素数=29
- 素数=31
- 素数=37
- 素数=41
- 素数=43
- 素数=47
- 素数=53
- 素数=59
- 素数=61
- 素数=67
- 素数=71
- 素数=73
- 素数=79
- 素数=83
- 素数=89
- 素数=97
- 素数=101
- 素数=103
- 素数=107
- 素数=109
- 素数=113
- 素数=127
- 素数=131
- 素数=137
- 素数=139
- 素数=149
- 素数=151
- 素数=157
- 素数=163
- 素数=167
- 素数=173
- 素数=179
- 素数=181
- 素数=191
- 素数=193
- 素数=197
- 素数=199
- main()退出
- package main
-
- import (
- "fmt"
- )
-
- //使用select解决管道阻塞问题
-
- func main() {
-
- intChan := make(chan int, 10)
- for i := 0; i < 10; i++ {
- intChan <- i
- }
-
- stringChan := make(chan string, 5)
- for i := 0; i < 5; i++ {
- stringChan <- "hello" + fmt.Sprintf("%d", 5)
- }
-
- //传统的方法遍历管道,如果不关闭会阻塞,会遭遇deadlock
- //有可能不好确定什么时候关闭管道
- //使用select解决
-
- for {
- select {
- //注意:如果intChan一直没有关闭,不会一直阻塞而deadlock
- //会自动的到下一个case
- case v := <-intChan:
- fmt.Println("从intChan读取数据 ", v)
- //time.Sleep(time.Second)
- case v := <-stringChan:
- fmt.Println("从stringChan读取数据 ", v)
- //time.Sleep(time.Second)
- default:
- fmt.Println("都读取不到了,不玩了")
- return
- }
- }
- }
- package main
-
- import (
- "fmt"
- "time"
- )
-
- // goroutine中使用recover可以解决协程中出现panic,导致程序崩溃问题
- func sayHello() {
- for i := 0; i < 10; i++ {
- time.Sleep(time.Second)
- fmt.Println("Hello world")
- }
-
- }
-
- func test() {
- //这里我们使用defer+recover
- defer func() {
- //捕获test抛出的panic
- //捕获了以后,这个协程发生错误不影响其他协程
- if err := recover(); err != nil {
- fmt.Println("test() 发生错误", err)
- }
- }()
-
- //定义了一个map,让它发生错误
- var myMap map[int]string
- myMap[0] = "Golang" //error
- }
- func main() {
- go sayHello()
-
- //panic: assignment to entry in nil map
- //报错引起整个程序崩溃
- go test()
- for i := 0; i < 10; i++ {
- fmt.Println("main() ok=", i)
- time.Sleep(time.Second)
- }
- }