Go简单实现协程池的实现示例

目录
  • MPG模型
  • 通道的特性

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

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

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

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

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

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来监听任务。【代码仅用作实现原理,想更优雅可以在该原理基础上自行优化】

废话不多说直接上代码!

package main

import (
	"strconv"
	"time"
)

/**
协程池
 */
//全局任务管道地址数组
var arr []*chan func()
//启动任务数量
var num = 10
//默认管道下标0
var index = 0
//任务开关
var static = false
func run(f *chan func()){
	println("等待咯")
	for static == true {
		select {
			case fu:=<-*f :     // 检测有没有数据可读
				// 一旦成功读取到数据,则进行该case处理语句
				fu()
			default:
				//println(f)
				//println("无数据")
		}
		time.Sleep(time.Duration(1)*time.Second)
	}
}
//启动任务函数
func Start(){
	static = true
	for i:=0;i<num;i++ {
		//make一个管道地址
		c:=make(chan func(),1)
		println(&c)
		//将该地址存入全局数组中
		arr = append(arr,&c)
		//地址传入任务函数
		go run(&c)
	}
}
//插入任务
func add(str string) {
	//此处不是很优雅,自行优化实现。
	if(index >= num-1){
		index = 0
	}else{
		index++
	}
	//向地址管道传入函数
	*arr[index] <- func() {
		println(str)
	}
}
//停止任务
func stop()  {
	//终止任务for
	static = false
	//清空管道数组
	arr = []*chan func(){}
}
func main() {
	Start()
	println("开始执行写入管道")
	println(len(arr))
	for i:=0;i<1000000000;i++ {
		add("传入的i:"+strconv.Itoa(i))
	}
	time.Sleep(time.Duration(2)*time.Second)
	stop()
	//time.Sleep(time.Duration(100)*time.Second)
}

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

到此这篇关于Go简单实现协程池的实现示例的文章就介绍到这了,更多相关Go 协程池内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Golang协程池gopool设计与实现

    目录 Goroutine 协程池 gopool 核心实现 Pool Task Worker 整体来看 三个角色的定位 使用 sync.Pool 进行性能优化 Goroutine Goroutine 是 Golang 提供的一种轻量级线程,我们通常称之为「协程」,相比较线程,创建一个协程的成本是很低的.所以你会经常看到 Golang 开发的应用出现上千个协程并发的场景. Goroutine 的优势: 与线程相比,Goroutines 成本很低. 它们的堆栈大小只有几 kb,堆栈可以根据应用程序的需

  • GO实现协程池管理的方法

    使用channel实现协程池 通过 Channel 实现 Goroutine Pool,缺点是会造成协程的频繁开辟和注销,但好在简单灵活通用. package main import ( "fmt" "io/ioutil" "net/http" "sync" ) // Pool goroutine Pool type Pool struct { queue chan int wg *sync.WaitGroup } // Ne

  • golang协程池设计详解

    Why Pool go自从出生就身带"高并发"的标签,其并发编程就是由groutine实现的,因其消耗资源低,性能高效,开发成本低的特性而被广泛应用到各种场景,例如服务端开发中使用的HTTP服务,在golang net/http包中,每一个被监听到的tcp链接都是由一个groutine去完成处理其上下文的,由此使得其拥有极其优秀的并发量吞吐量 for { // 监听tcp rw, e := l.Accept() if e != nil { ....... } tempDelay = 0

  • golang协程池模拟实现群发邮件功能

    比如批量群发邮件的功能 因为发送邮件是个比较耗时的操作, 如果是传统的一个个执行 , 总体耗时比较长 可以使用golang实现一个协程池 , 并行发送邮件 pool包下的pool.go文件 package pool import "log" //具体任务,可以传参可以自定义操作 type Task struct { Args interface{} Do func(interface{})error } //协程的个数 var Nums int //任务通道 var JobChanne

  • golang 40行代码实现通用协程池

    代码仓库 goroutine-pool golang的协程管理 golang协程机制很方便的解决了并发编程的问题,但是协程并不是没有开销的,所以也需要适当限制一下数量. 不使用协程池的代码(示例代码使用chan实现,代码略啰嗦) func (p *converter) upload(bytes [][]byte) ([]string, error) { ch := make(chan struct{}, 4) wg := &sync.WaitGroup{} wg.Add(len(bytes))

  • Go简单实现协程池的实现示例

    目录 MPG模型 通道的特性 首先就是进程.线程.协程讲解老三样. 进程: 本质上是一个独立执行的程序,进程是操作系统进行资源分配和调度的基本概念,操作系统进行资源分配和调度的一个独立单位. 线程: 是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一个进程中可以并发多个线程,每条线程执行不同的任务,切换受系统控制. 协程:  又称为微线程,是一种用户态的轻量级线程,协程不像线程和进程需要进行系统内核上的上下文切换,协程的上下文切换是由用户自己决定的,有自己的上下

  • java基于quasar实现协程池的方法示例

    业务场景:golang与swoole都拥抱了协程,在同任务并发数量下,协程可比线程多几倍.所以最近在查询java时了解java本身是没有协程的,但是某牛自行实现了协程,也就是本文的主角quasar(纤程)!在csdn中基本都是对它的基本使用,用法和线程差不多.不过没看到谁公开一下手写协程池的骚操作(谁会直接new它用?那是没挨过社会的毒打呀~) 一个线程可以多个协程,一个进程也可以单独拥有多个协程. 线程进程都是同步机制,而协程则是异步. 协程能保留上一次调用时的状态,每次过程重入时,就相当于进

  • PHP实现简单的协程任务调度demo示例

    本文实例讲述了PHP实现简单的协程任务调度.分享给大家供大家参考,具体如下: <?php class Task { protected $taskId; protected $coroutine; protected $sendValue = null; protected $beforeFirstYield = true; public function __construct($taskId, Generator $coroutine) { $this->taskId = $taskId;

  • Go简单实现协程方法

    目录 为什么需要协程 协程的本质 协程如何在线程中执行 GMP调度模型 协程并发 为什么需要协程 协程的本质是将一段数据的运行状态进行打包,可以在线程之间调度,所以协程就是在单线程的环境下实现的应用程序级别的并发,就是把本来由操作系统控制的切换+保存状态在应用程序里面实现了. 所以我们需要协程的目的其实就是它更加节省资源.可以在有限的资源内支持更高的并发,体现在以下三个方面: 资源利用:程可以利用任何的线程去运行,不需要等待CPU的调度. 快速调度:协程可以快速地调度(避开了系统调用和切换),快

  • grpool goroutine池协程管理

    目录 前言 名词概念 使用示例 踩坑之旅 常犯的错误 分析原因 使用grpool 错误代码 正确代码 总结 前言 goroutine协程非常轻量级,这也是为什么go支持高并发,但是goroutine频繁创建销毁对GC的压力比较大. grpool的作用就是复用goroutine,减少频繁创建销毁的性能消耗. 名词概念 Pool: goroutine池,用于管理若干可复用的goroutine协程资源 Worker: 池对象中参与任务执行的goroutine,一个worker可以执行若干个job,直到

随机推荐