Go簡單實現協程池的實現示例

首先就是進程、線程、協程講解老三樣。

進程: 本質上是一個獨立執行的程序,進程是操作系統進行資源分配和調度的基本概念,操作系統進行資源分配和調度的一個獨立單位。

線程: 是操作系統能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運作單位。一個進程中可以並發多個線程,每條線程執行不同的任務,切換受系統控制。

協程:  又稱為微線程,是一種用戶態的輕量級線程,協程不像線程和進程需要進行系統內核上的上下文切換,協程的上下文切換是由用戶自己決定的,有自己的上下文,所以說是輕量級的線程,也稱之為用戶級別的線程就叫協程,一個線程可以多個協程,線程進程都是同步機制,而協程則是異步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 協程池內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: