• Go简单实现协程池


    首先就是进程、线程、协程讲解老三样。

    进程: 本质上是一个独立执行的程序,进程是操作系统进行资源分配和调度的基本概念,操作系统进行资源分配和调度的一个独立单位。

    线程: 是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一个进程中可以并发多个线程,每条线程执行不同的任务,切换受系统控制。


    协程:  又称为微线程,是一种用户态的轻量级线程,协程不像线程和进程需要进行系统内核上的上下文切换,协程的上下文切换是由用户自己决定的,有自己的上下文,所以说是轻量级的线程,也称之为用户级别的线程就叫协程,一个线程可以多个协程,线程进程都是同步机制,而协程则是异步Java的原生语法中并没有实现协程,目前python、Lua和GO等语言支持。


    关系:一个进程可以有多个线程,它允许计算机同时运行两个或多个程序。线程是进程的最小执行单位,CPU
    的调度切换的是进程和线程,进程和线程多了之后调度会消耗大量的CPU,CPU上真正运行的是线程,线程可
    以对应多个协程。

     golang协程

    MPG模型

    Go协程中有三个关键实体:

    • M(machine): 工作线程,由操作系统调度。应该就是通常所说的内核线程。
    • P(processor): 处理器(非CPU),代表着运行Go代码的必要资源,以及调度goroutine的能力。个人觉得可以当作拥有自主调度权的算法模块,用于工作窃取(work stealing)
    • G(gooutine): Go协程,轻量级用户线程。主要包含执行栈调度管理器。这里的调度管理器指的是,统一并管理调度资源,等待被调度。

     

    Go协程的特点

    (1)有独立的栈空间

    (2)共享程序的堆空间

    (3)协程调度由用户控制(进程的控制是有操作系统控制,程序员不能控制)

    (4)协程是轻量级的线程

     

    通道的特性

    Go语言中的通道(channel)是一种特殊的类型。在任何时候,同时只能有一个 goroutine 访问通道进行发送和获取数据。goroutine 间通过通道就可以通信。

    通道像一个传送带或者队列,总是遵循先入先出(First In First Out)的规则,保证收发数据的顺序。

    当然协程的轻量性并不代表可以随意滥用,毕竟还是存在资源的消耗。本文主要讲解go的协程池的实现原理,利用select来监听任务。【代码仅用作实现原理,想更优雅可以在该原理基础上自行优化】

    废话不多说直接上代码!

    1. package main
    2. import (
    3. "strconv"
    4. "time"
    5. )
    6. /**
    7. 协程池
    8. */
    9. //全局任务管道地址数组
    10. var arr []*chan func()
    11. //启动任务数量
    12. var num = 10
    13. //默认管道下标0
    14. var index = 0
    15. //任务开关
    16. var static = false
    17. func run(f *chan func()){
    18. println("等待咯")
    19. for static == true {
    20. select {
    21. case fu:=<-*f : // 检测有没有数据可读
    22. // 一旦成功读取到数据,则进行该case处理语句
    23. fu()
    24. default:
    25. //println(f)
    26. //println("无数据")
    27. }
    28. time.Sleep(time.Duration(1)*time.Second)
    29. }
    30. }
    31. //启动任务函数
    32. func Start(){
    33. static = true
    34. for i:=0;i<num;i++ {
    35. //make一个管道地址
    36. c:=make(chan func(),1)
    37. println(&c)
    38. //将该地址存入全局数组中
    39. arr = append(arr,&c)
    40. //地址传入任务函数
    41. go run(&c)
    42. }
    43. }
    44. //插入任务
    45. func add(str string) {
    46. //此处不是很优雅,自行优化实现。
    47. if(index >= num-1){
    48. index = 0
    49. }else{
    50. index++
    51. }
    52. //向地址管道传入函数
    53. *arr[index] <- func() {
    54. println(str)
    55. }
    56. }
    57. //停止任务
    58. func stop() {
    59. //终止任务for
    60. static = false
    61. //清空管道数组
    62. arr = []*chan func(){}
    63. }
    64. func main() {
    65. Start()
    66. println("开始执行写入管道")
    67. println(len(arr))
    68. for i:=0;i<1000000000;i++ {
    69. add("传入的i:"+strconv.Itoa(i))
    70. }
    71. time.Sleep(time.Duration(2)*time.Second)
    72. stop()
    73. //time.Sleep(time.Duration(100)*time.Second)
    74. }

    原理很简单,就是合理使用select来监听管道是否有数据,协程池的实现就是合理利用管道。可以根据该思路来进行优化封装一个属于自己的协程池哦~

    对于优化建议,有牛可评论,相互学习!

  • 相关阅读:
    通过源码了解Java的自动装箱拆箱
    摄影后期色彩管理流程(Lightroom篇)
    海量数据分析更快、更稳、更准。GaussDB(for MySQL) HTAP只读分析特性详解
    Multi-granularity Correspondence Learning from Long-term Noisy Videos--论文笔记
    jeecgBoot 路由配置和自定义路由配置
    C++ 继承
    【机器学习算法】决策树-4 CART算法和CHAID算法
    【Python】read() || readline() || readlines()-笔记
    如何在JVS低代码表单配置中实现数据的高效管理?
    太原元宇宙3D交互展厅搭建让观众能够与企业进行更加紧密的沟通和交流
  • 原文地址:https://blog.csdn.net/weixin_47723549/article/details/125498377