1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. )
  6. //go的协程和python的协程 - 网上有些人可能喜欢拿web框架来做性能对比
  7. //go的gin beego - flask/django + gevent性能对比 - 这个不科学的 uwsgi部署
  8. //flask/django 只是一个web框架 本身不提供 启动多线程 多进程来提高并发的能力 一般使用中间件
  9. //tornado sanic fastapi /asyncio 协程库 我们就不再使用python的多线程来对比了
  10. //只要大家懂了任何一门语言的协程 其他语言的协程都很好理解 GMP调度模型
  11. //1.大家都开启100w个协程 2.使用的简单性
  12. func p() {
  13. //fmt.Println("协程")
  14. for i := 1; i <= 100000; i++ {
  15. go func(n int) {
  16. fmt.Println(n)
  17. }(i)
  18. }
  19. }
  20. func main() {
  21. //闭包的特性
  22. //主死从随
  23. //go p()
  24. for i := 1; i <= 300000; i++ {
  25. go func(n int) {
  26. fmt.Println(n)
  27. time.Sleep(time.Second)
  28. }(i)
  29. }
  30. time.Sleep(time.Second*10)
  31. }
  32. //goroutine
  33. //python java c++ 多线程和多线程编程
  34. //go 语言诞生的比较晚 web 2.0 开发主键主流 高并发
  35. //多线程 - 每个线程占用的内存比较多 而且系统切换开销很大 上千绿程/轻量级线程 - 协程 - 用户态线程
  36. //go语言一开始的时候就没有让我们取实例化一个线程 - 协程 go 没有历史包袱
  37. //nodejs python3.6 那为什么go的协程为什么会这么火
  38. //python中有两种编程模式 1.多线程和多进程来进行并发编程 2. 使用协程进程并发编程 很多的库是基于多线程和多进程开发的
  39. //除非某一天所有的库 大部分的库都支持了协程

channel_test

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. "time"
  6. )
  7. var wg sync.WaitGroup
  8. //消费者消费
  9. func consumer(queue chan int) {
  10. defer wg.Done()
  11. //data := <-queue
  12. for {
  13. data,ok := <- queue
  14. if !ok{
  15. break
  16. }
  17. fmt.Println(data)
  18. time.Sleep(time.Second)
  19. }
  20. //for data := range queue {
  21. // fmt.Println(data)
  22. // time.Sleep(time.Second)
  23. //}
  24. //fmt.Println(data)
  25. }
  26. func main() {
  27. /*
  28. channel 提供了一种通信机制 定向发消息 消息队列 python java
  29. */
  30. //1. 定义一个channel
  31. var msg chan int
  32. //2. 初始化这个channel 两种方式
  33. msg = make(chan int) //第一种初始化方式 无缓冲
  34. //msg = make(chan int, 1)
  35. //第二种初始化方式 有缓冲空间
  36. //3. 在go语言中 使用make初始化的有三种 slice map channel
  37. //go func(queue chan int) {
  38. // data := <-msg //将箭头右边的值放到左边
  39. // fmt.Println(data)
  40. //}(msg)
  41. //msg <- 3 //fatal error: all goroutines are asleep - deadlock!
  42. wg.Add(1)
  43. go consumer(msg)
  44. msg <- 1 //你这个管道看起来好像就是一个有空间的数组
  45. //go consumer(msg)
  46. msg <- 2 //fatal error: all goroutines are asleep - deadlock!
  47. //关闭channel 1.已经关闭的channel不能再发送数据了 2.已经关闭的channel 消费者能继续取数据吗?
  48. //2可以 直到数据取完为止
  49. close(msg)
  50. //go consumer(msg)
  51. wg.Wait()
  52. }

channel_type

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. "time"
  6. )
  7. var wg sync.WaitGroup
  8. func consumer(queue <-chan int) {
  9. defer wg.Done()
  10. for {
  11. data, ok := <-queue
  12. if !ok {
  13. break
  14. }
  15. fmt.Println(data)
  16. time.Sleep(time.Second)
  17. }
  18. }
  19. func stock(queue chan <- int) {
  20. defer wg.Done()
  21. for {
  22. queue <- 1
  23. time.Sleep(time.Second)
  24. }
  25. }
  26. func main() {
  27. //有没有缓冲 1.有缓冲 2.无缓冲
  28. //双向的还是单向的 为了安全 还提供了单向channel
  29. var msg chan int //双向 可以把双向的channel赋值给单向的channel
  30. //var msg chan<- int //仅发送
  31. //var msg <-chan int //仅接收
  32. msg = make(chan int, 10)
  33. //data := <-msg //无效运算: <-msg (从仅发送类型 chan<- int 接收)
  34. //fmt.Println(data)
  35. wg.Add(1)
  36. go consumer(msg) //普通的channel 可以直接转换为单向的channel
  37. msg <- 1
  38. close(msg)
  39. wg.Wait()
  40. /*
  41. 1
  42. 等待返回值
  43. 2
  44. 等待返回值
  45. 1
  46. 2
  47. */
  48. }

context_test

  1. package main
  2. import (
  3. "context"
  4. "fmt"
  5. "sync"
  6. "time"
  7. )
  8. var wg sync.WaitGroup
  9. //1.监控全局变量 来完成
  10. //2.通过channel
  11. //var stop bool
  12. //var stop chan bool = make(chan bool)
  13. //3.刚才的两种方式 这种方案并不统一 go1.7 context机制
  14. //父的context
  15. //父的context取消 那么这个父的context生成的context也会被取消
  16. func cpuInfo(ctx context.Context) {
  17. defer wg.Done()
  18. //ctx2, _ := context.WithCancel(ctx)
  19. context.WithDeadline(ctx, time.Now())
  20. //a -> b -> c
  21. //context.WithTimeout()
  22. //context.WithValue()
  23. //go memoryInfo(ctx2)
  24. for {
  25. //if stop {
  26. // break
  27. //}
  28. //select {
  29. //case <-stop:
  30. // fmt.Println("退出CPU监控")
  31. // return
  32. //default:
  33. // time.Sleep(time.Second*2)
  34. // fmt.Println("CPU信息读取完成")
  35. //}
  36. select {
  37. case <-ctx.Done():
  38. fmt.Println("监控退出")
  39. return
  40. default:
  41. time.Sleep(time.Second)
  42. fmt.Println("获取cpu信息成功")
  43. }
  44. }
  45. }
  46. func memoryInfo(ctx context.Context) {
  47. defer wg.Done()
  48. for {
  49. select {
  50. case <-ctx.Done():
  51. fmt.Println("监控内存退出")
  52. return
  53. default:
  54. time.Sleep(time.Second)
  55. fmt.Println("获取内存信息成功")
  56. }
  57. }
  58. }
  59. func main() {
  60. //现在启动一个goroutine去监控某台服务器的cpu使用情况
  61. wg.Add(1)
  62. //ctx, cancel := context.WithCancel(context.Background())
  63. ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) //有一种自动的机制在里面
  64. //ctx, cancel := context.WithDeadline(context.Background(), time.Second*2) //有一种自动的机制在里面
  65. go cpuInfo(ctx)
  66. time.Sleep(time.Second)
  67. cancel()
  68. //go memoryInfo(ctx)
  69. //现在希望可以中断CPU的信息读取
  70. //time.Sleep(time.Second * 5)
  71. //cancel()
  72. //context在web开发中非常的常用 grpc 每个接口调用都会传递context gin的http接口也会有
  73. //stop <- true
  74. //stop = true
  75. wg.Wait()
  76. fmt.Println("信息监控完成")
  77. }

deadlock_test

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. )
  6. var wg sync.WaitGroup
  7. func consumer(msg chan int) {
  8. defer wg.Done()
  9. fmt.Println(<-msg)
  10. }
  11. func main() {
  12. var msg chan int
  13. msg = make(chan int)
  14. //当你进行 放数据到msg中的时候 这个时候会阻塞的
  15. // 阻塞之前会获取一把锁 这把锁什么时候释放 肯定要等到数据被消费
  16. wg.Add(1)
  17. go consumer(msg)
  18. msg <- 1
  19. wg.Wait()
  20. //channel是多个goroutine之间线程安全 如何保证的呢? 使用锁
  21. //如果你是没有缓冲的channel 在没有启动一个消费者之前 你放数据就会报错
  22. //data := <-msg
  23. //fmt.Println(data)
  24. fmt.Println("hello world")
  25. fmt.Println()
  26. }

lock_test

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. )
  6. /*
  7. 锁 - 资源竞争
  8. 1.按理说 最后的结果是0
  9. 2.实际的情况 1. 不是0 2.每次运行的结果不一样
  10. */
  11. var total int
  12. var wg sync.WaitGroup
  13. //互斥锁(同步问题) - 读写锁 同步数据 能不用锁就别用锁 - 性能下降
  14. //绝大多数的web系统来说 都是读多写少
  15. //有1w个人同时读数据库 A读的时候 B能读么? 为什么要加锁呢?100 - 1w - 100
  16. //立马我下单了 - 支付(会重新查一遍数据库 1w)
  17. //一定要加锁 写 和 读上面要加同一把锁 并发严重下降。
  18. //B读了一个数据,造成C读了数据产生影响吗? 一定是写和读之间造成的
  19. //如果这把锁之间可以做到 读之间不会产生影响 读写之间才会产生影响 那多好 读写锁
  20. var lock sync.Mutex
  21. func add() {
  22. defer wg.Done()
  23. for i := 0; i < 100000; i++ {
  24. //先把门锁上
  25. lock.Lock()
  26. total += 1
  27. //放开锁
  28. lock.Unlock()
  29. //1.从total中取值
  30. //2.将total+1
  31. //3.将total+1的计算结果放入到total中
  32. }
  33. }
  34. func sub(){
  35. defer wg.Done()
  36. for i := 0; i < 100000; i++ {
  37. //先把门锁上
  38. lock.Lock()
  39. total -= 1
  40. lock.Unlock()
  41. //放开锁
  42. }
  43. }
  44. func main() {
  45. wg.Add(2)
  46. go add()
  47. go sub()
  48. wg.Wait()
  49. fmt.Println(total)
  50. }

rwlock_test

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. "time"
  6. )
  7. /*
  8. 锁 - 资源竞争
  9. 1.按理说 最后的结果是0
  10. 2.实际的情况 1. 不是0 2.每次运行的结果不一样
  11. */
  12. var total int
  13. var wg sync.WaitGroup
  14. var lock sync.Mutex //互斥锁
  15. var rwLock sync.RWMutex //读写锁
  16. func read() {
  17. defer wg.Done()
  18. rwLock.RLock()
  19. fmt.Println("开始读取数据")
  20. time.Sleep(time.Second)
  21. fmt.Println("读取成功")
  22. rwLock.RUnlock()
  23. }
  24. func write(){
  25. defer wg.Done()
  26. rwLock.Lock()
  27. fmt.Println("开始修改数据")
  28. time.Sleep(time.Second*2)
  29. fmt.Println("修改成功")
  30. rwLock.Unlock()
  31. }
  32. func main() {
  33. wg.Add(8)
  34. for i := 0; i < 5; i++ {
  35. go read()
  36. }
  37. for i := 0; i < 3; i++ {
  38. go write()
  39. }
  40. wg.Wait()
  41. fmt.Println(total)
  42. }

select_test

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. )
  6. func main() {
  7. /*
  8. go语言提供了select的功能,作用与channel之上的 多路复用
  9. select 会随机公平的选择一个case语句执行
  10. select的应用场景 1.timeout的超时机制 2.判断某个channel是否阻塞
  11. */
  12. //timeout := false
  13. timeout := make(chan bool, 2)
  14. go func() {
  15. //该goroutine如果执行时间超过了5s 那么就报告给主的goroutine
  16. //fmt.Println("结束")
  17. time.Sleep(time.Second * 5)
  18. timeout <- true
  19. }()
  20. timeout2 := make(chan bool, 2)
  21. go func() {
  22. //该goroutine如果执行时间超过了1s 那么就报告给主的goroutine
  23. //fmt.Println("结束")
  24. time.Sleep(time.Second * 1)
  25. timeout2 <- true
  26. }()
  27. select {
  28. case <-timeout:
  29. fmt.Println("超时了1")
  30. case <-timeout2:
  31. fmt.Println("超时了2")
  32. default:
  33. fmt.Println("继续下一次")
  34. }
  35. //fmt.Println(<-timeout)
  36. //for {
  37. // if timeout {
  38. // fmt.Println("结束")
  39. // break
  40. // }
  41. // time.Sleep(time.Millisecond * 10)
  42. //}
  43. //ch1 := make(chan int, 1)
  44. //ch2 := make(chan int, 1)
  45. //ch1 <- 1
  46. //ch2 <- 2
  47. ////随机选择一个
  48. //select {
  49. //case data := <-ch1:
  50. // fmt.Println(data)
  51. //case data := <-ch2:
  52. // fmt.Println(data)
  53. //}
  54. }

waitgroup

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. )
  6. //如何解决主的goroutine在子协程结束后自动结束
  7. var wg sync.WaitGroup
  8. //WaitGroup 提供了三个很有用的函数
  9. /*
  10. Add
  11. Done
  12. Wait
  13. Add的数量必须和Done的数量相等
  14. */
  15. func f(i int) {
  16. //如果不写,fatal error: all goroutines are asleep - deadlock!
  17. //defer wg.Done()
  18. fmt.Println(i)
  19. }
  20. func main() {
  21. wg.Add(5)
  22. for i := 0; i < 5; i++ {
  23. go f(i)
  24. //go func(n int) {
  25. //一般利用defer机制
  26. //defer wg.Done()
  27. //fmt.Println(n)
  28. //wg.Done()
  29. //}(i)
  30. }
  31. wg.Wait()
  32. }