gopool 源碼分析

gopool

gopool是字節跳動開源節流的gopkg包中協程池的一個實現。

關鍵結構

協程池:

type pool struct {// The name of the poolname string// capacity of the pool, the maximum number of goroutines that are actually working// 協程池的最大容量cap int32// Configuration informationconfig *Config// linked list of tasks// 任務鏈表taskHead  *tasktaskTail  *tasktaskLock  sync.MutextaskCount int32// Record the number of running workers// 運行中的協程數workerCount int32// This method will be called when the worker panic// 出現 panic 時調用、 panicHandler func(context.Context, interface{})
}

任務:

type task struct {ctx context.Contextf   func()next *task
}

worker:

type worker struct {pool *pool
}

源碼分析

先說一下 gopool 的工作流程:

  1. 通過 Go 或者 CtxGo 方法調用
  2. 從 taskPool 中取出一個 t
  3. 如果當前的積壓task達到閾值且worker(工作協程)的數量未達到上限,則新建一個worker。

pool.cap 最大工作協程與實際運行的最大協程可能會存在誤差。因為新建worker這塊不是原子操作:

if (atomic.LoadInt32(&p.taskCount) >= p.config.ScaleThreshold && p.WorkerCount() < atomic.LoadInt32(&p.cap)) || p.WorkerCount() == 0 {// 工作協程加1p.incWorkerCount()w := workerPool.Get().(*worker)w.pool = pw.run()}

worker 的最大數量不會超過pool.cap 。worker run 流程比較簡單:

  1. 循環的從 pool 中取出 task 執行

為了方便查看源碼,我把相關代碼都粘到了下面的,詳細流程如下:

var workerPool sync.Poolvar taskPool sync.Pool// 初始化 taskPool
func init() {taskPool.New = newTask
}func (p *pool) Go(f func()) {p.CtxGo(context.Background(), f)
}func (p *pool) CtxGo(ctx context.Context, f func()) {// 從 taskPool 中取 task,避免頻繁創建銷毀t := taskPool.Get().(*task)t.ctx = ctx// 賦值執行函數t.f = f// 將 t 添加到任務鏈表里,加鎖保證并發安全p.taskLock.Lock()if p.taskHead == nil {p.taskHead = tp.taskTail = t} else {p.taskTail.next = tp.taskTail = t}p.taskLock.Unlock()// 任務鏈表數量原子加 1atomic.AddInt32(&p.taskCount, 1)// The following two conditions are met:// 1. the number of tasks is greater than the threshold.// 2. The current number of workers is less than the upper limit p.cap.// or there are currently no workers.// 滿足以下兩個條件:// 1.任務數大于等于設置的閾值(默認為1)// 2.當前的協程數低于上限,或者目前沒有工人if (atomic.LoadInt32(&p.taskCount) >= p.config.ScaleThreshold && p.WorkerCount() < atomic.LoadInt32(&p.cap)) || p.WorkerCount() == 0 {// 工作協程加1p.incWorkerCount()w := workerPool.Get().(*worker)w.pool = pw.run()}
}func (w *worker) run() {go func() {for {var t *taskw.pool.taskLock.Lock()if w.pool.taskHead != nil {// 取出任務t = w.pool.taskHeadw.pool.taskHead = w.pool.taskHead.nextatomic.AddInt32(&w.pool.taskCount, -1)}// 沒有任務則結束if t == nil {// if there's no task to do, exitw.close()w.pool.taskLock.Unlock()w.Recycle()return}w.pool.taskLock.Unlock()func() {defer func() {if r := recover(); r != nil {if w.pool.panicHandler != nil {w.pool.panicHandler(t.ctx, r)} else {msg := fmt.Sprintf("GOPOOL: panic in pool: %s: %v: %s", w.pool.name, r, debug.Stack())logger.CtxErrorf(t.ctx, msg)}}}()// 執行t.f()}()t.Recycle()}}()
}func (t *task) Recycle() {t.zero()taskPool.Put(t)
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/82922.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/82922.shtml
英文地址,請注明出處:http://en.pswp.cn/web/82922.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【工作記錄】接口功能測試總結

如何對1個接口進行接口測試 一、單接口功能測試 1、接口文檔信息 理解接口文檔的內容&#xff1a; 請求URL: https://[ip]:[port]/xxxserviceValidation 請求方法: POST 請求參數: serviceCode(必填), servicePsw(必填) 響應參數: status, token 2、編寫測試用例 2.1 正…

Linux中su與sudo命令的區別:權限管理的關鍵差異解析

&#x1f49d;&#x1f49d;&#x1f49d;歡迎蒞臨我的博客&#xff0c;很高興能夠在這里和您見面&#xff01;希望您在這里可以感受到一份輕松愉快的氛圍&#xff0c;不僅可以獲得有趣的內容和知識&#xff0c;也可以暢所欲言、分享您的想法和見解。 推薦&#xff1a;「storms…

樂觀鎖與悲觀鎖的實現和應用

樂觀鎖與悲觀鎖&#xff1a;原理、實現與應用詳解 在并發編程和數據庫操作中&#xff0c;樂觀鎖和悲觀鎖是兩種重要的并發控制策略&#xff0c;它們在原理、實現方式和應用場景上存在顯著差異。下面我們將通過圖文結合的方式&#xff0c;深入探討這兩種鎖機制。 一、基本概念 1…

ios蘋果系統,js 滑動屏幕、錨定無效

現象&#xff1a;window.addEventListener監聽touch無效&#xff0c;劃不動屏幕&#xff0c;但是代碼邏輯都有執行到。 scrollIntoView也無效。 原因&#xff1a;這是因為 iOS 的觸摸事件處理機制和 touch-action: none 的設置有關。ios有太多得交互動作&#xff0c;從而會影響…

Redis主從復制原理二 之 主從復制工作流程

概述 本文緊接「Redis主從復制的原理一 之 概述」&#xff0c;詳細介紹了Redis的主從服務過程及原理。 主從復制工作流程 主從復制過程大體可以分為3個階段&#xff1a; 建立連接階段&#xff08;即準備階段&#xff09;數據同步階段命令傳播階段 階段一&#xff1a;建立連接階…

Markdown基礎(1.2w字)

1. Markdown基礎 這次就沒目錄了&#xff0c;因為md格式太亂了寫示例&#xff0c;展示那些都太亂了&#xff0c;導致目錄很亂。 &#xff08;我是XX&#xff0c;出現了很多錯誤&#xff0c;有錯誤和我說&#xff09; 1.1 Markdown簡介 Markdown是一種輕量級的標記語言&#…

JAVA-springboot log日志

SpringBoot從入門到精通-第8章 日志的操作 一、Spring Boot默認的日志框架 SpringBoot支持很多種日志框架&#xff0c;通常情況下&#xff0c;這些日志框架都是由一個日志抽象層和一個日志實現層搭建而成的&#xff0c;日志抽象層是為記錄日志提供的一套標準且規范的框架&…

Vue 渲染 Markdown 文件完全指南

前言 大家好&#xff0c;我是一諾&#xff0c;今天分享的是vue中渲染markdown文件。這是一個常見的需求&#xff0c;比如用戶隱私協議頁、技術說明等文檔頁面~ 本文將詳細介紹如何在 Vue 中渲染 Markdown 文件&#xff0c;并美化代碼塊的顯示效果。 基礎概念 什么是 Markdo…

Science Robotics:UCLA 賀曦敏團隊綜述自主軟體機器人

在機器人中實現類似生命的自主性一直是研究的方向&#xff0c;但目前大多數軟體機器人仍依賴外部刺激操控來產生持續運動。為了實現能夠自我調節感知 、 決策和驅動的自主物理智能&#xff08;autonomous physical intelligence&#xff0c;API&#xff09;&#xff0c;一種有前…

基于LangChain構建高效RAG問答系統:向量檢索與LLM集成實戰

基于LangChain構建高效RAG問答系統&#xff1a;向量檢索與LLM集成實戰 在本文中&#xff0c;我將詳細介紹如何使用LangChain框架構建一個完整的RAG&#xff08;檢索增強生成&#xff09;問答系統。通過向量檢索獲取相關上下文&#xff0c;并結合大語言模型&#xff0c;我們能夠…

【Java學習筆記】SringBuffer類(重點)

StringBuffer&#xff08;重點&#xff09; 1. 基本介紹 &#xff08;1&#xff09;StringBuffer是可變的字符序列&#xff0c;可以對字符串內容驚醒增刪 &#xff08;2&#xff09;很多方法喝String相同&#xff0c;但StringBuffer可變長度 &#xff08;3&#xff09;Strin…

計算機網絡領域所有CCF-A/B/C類期刊匯總!

本期小編統計了【計算機網絡】領域CCF推薦所有期刊的最新影響因子&#xff0c;分區、年發文量以及投稿經驗&#xff0c;供大家參考&#xff01; CCF-A類 1 IEEE Journal on Selected Areas in Communications 【影響因子】13.8 【期刊分區】JCR1區&#xff0c;中科院1區TOP …

AI-Sphere-Butler之如何啟動AI全能管家教程(WSL測試環境下適用)

環境&#xff1a; Ubuntu20.04 WSL2 問題描述&#xff1a; AI-Sphere-Butler之如何啟動AI全能管家教程(WSL測試環境下適用) 解決方案&#xff1a; 打開管家大模型 1.運行大模型在cmd下輸入&#xff1a; ollama run qwen2.5-3bnsfwny運行管家 數字人運行腳本&#xff…

【python深度學習】Day 47 注意力熱圖可視化

知識點&#xff1a;熱力圖 作業&#xff1a;對比不同卷積層熱圖可視化的結果 一、概念 為了方便觀察輸出&#xff0c;將特征圖進行可視化。特征圖本質就是不同的卷積核的輸出&#xff0c;淺層指的是離輸入圖近的卷積層&#xff0c;淺層卷積層的特征圖通常較大&#xff0c;而深層…

C#語音識別:使用Whisper.net實現語音識別

C#語音識別&#xff1a;使用Whisper.net實現語音識別 在當今數字化時代&#xff0c;語音識別技術已廣泛應用于智能助手、語音轉文字、會議記錄等眾多領域。對于 C# 開發者而言&#xff0c;如何快速、高效地實現語音識別功能呢&#xff1f;今天&#xff0c;我們就來介紹一個強大…

開源分享|適合初創商家的餐飲系統,基于thinkphp8+element-plus

一、項目介紹 三勾餐飲點餐連鎖版系統是一個基于thinkphp8element-plusuniapp打造的面向開發的小程序商城的全面解決方案&#xff0c;旨在為連鎖餐飲企業提供高效的點餐與管理服務。該系統支持多端應用發布&#xff0c;包括微信小程序、H5、安卓及iOS平臺&#xff0c;實現數據…

rec_pphgnetv2完整代碼學習(一)

rec_pphgnetv2是paddleocr_v5中的重要改進&#xff0c;因此對其完整代碼進行學習十分之有必要。 一、IdentityBasedConv1x1 這段代碼定義了 IdentityBasedConv1x1 類&#xff0c;它是 PaddleOCRv5 中 rec_pphgnetv2 模型的關鍵改進之一。該層通過將恒等映射&#xff08;Ident…

vue3+dify從零手擼AI對話系統

vue3dify從零手擼AI對話系統 前言 近年來&#xff0c;人工智能技術呈現爆發式增長&#xff0c;其應用已深度滲透至各行各業。甚至家里長輩們也開始借助AI工具解決日常問題。作為程序員群體&#xff0c;我們更應保持技術敏銳度&#xff0c;緊跟這波浪潮。 回溯求學時期&#xf…

robot_lab train的整體邏輯

Go2機器人推理(Play)流程詳細分析 概述 本文檔詳細分析了使用命令 python scripts/rsl_rl/base/play.py --task RobotLab-Isaac-Velocity-Rough-Unitree-Go2-v0 進行Go2機器人推理的完整流程&#xff0c;基于實際的代碼實現&#xff0c;包括模型加載、環境配置調整、推理循環…

Python Day45

Task&#xff1a; 1.tensorboard的發展歷史和原理 2.tensorboard的常見操作 3.tensorboard在cifar上的實戰&#xff1a;MLP和CNN模型 效果展示如下&#xff0c;很適合拿去組會匯報撐頁數&#xff1a; 作業&#xff1a;對resnet18在cifar10上采用微調策略下&#xff0c;用tens…