首页
技术小册
AIGC
面试刷题
技术文章
MAGENTO
云计算
视频课程
源码下载
PDF书籍
「涨薪秘籍」
登录
注册
01|前世今生:你不得不了解的Go的历史和现状
02|拒绝“Hello and Bye”:Go语言的设计哲学是怎么一回事?
03|配好环境:选择一种最适合你的Go安装方法
04|初窥门径:一个Go程序的结构是怎样的?
05|标准先行:Go项目的布局标准是什么?
06|构建模式:Go是怎么解决包依赖管理问题的?
07|构建模式:Go Module的6类常规操作
08|入口函数与包初始化:搞清Go程序的执行次序
09|即学即练:构建一个Web服务就是这么简单
10|变量声明:静态语言有别于动态语言的重要特征
11|代码块与作用域:如何保证变量不会被遮蔽?
12|基本数据类型:Go原生支持的数值类型有哪些?
13|基本数据类型:为什么Go要原生支持字符串类型?
14|常量:Go在“常量”设计上的创新有哪些?
15|同构复合类型:从定长数组到变长切片
16|复合数据类型:原生map类型的实现机制是怎样的?
17|复合数据类型:用结构体建立对真实世界的抽象
18|控制结构:if的“快乐路径”原则
19|控制结构:Go的for循环,仅此一种
20|控制结构:Go中的switch语句有哪些变化?
21|函数:请叫我“一等公民”
22|函数:怎么结合多返回值进行错误处理?
23|函数:怎么让函数更简洁健壮?
24|方法:理解“方法”的本质
25|方法:方法集合与如何选择receiver类型?
26|方法:如何用类型嵌入模拟实现“继承”?
27|即学即练:跟踪函数调用链,理解代码更直观
28|接口:接口即契约
29|接口:为什么nil接口不等于nil?
30|接口:Go中最强大的魔法
31|并发:Go的并发方案实现方案是怎样的?
32|并发:聊聊Goroutine调度器的原理
33|并发:小channel中蕴含大智慧
34|并发:如何使用共享变量?
35|即学即练:如何实现一个轻量级线程池?
36|打稳根基:怎么实现一个TCP服务器?(上)
37|代码操练:怎么实现一个TCP服务器?(中)
38|成果优化:怎么实现一个TCP服务器?(下)
39 | 驯服泛型:了解类型参数
40|驯服泛型:定义泛型约束
41 | 驯服泛型:明确使用时机
当前位置:
首页>>
技术小册>>
Go语言入门实战经典
小册名称:Go语言入门实战经典
### 35|即学即练:如何实现一个轻量级线程池? 在Go语言的学习与应用中,理解并掌握线程池(在Go中通常通过goroutine和channel来实现并发执行任务,这里的“线程池”概念可视为管理goroutine的一种模式)是非常重要的。线程池能有效减少goroutine的创建与销毁开销,控制并发执行的goroutine数量,避免过多的并发导致系统资源耗尽,如CPU过载或内存不足。下面,我们将详细探讨如何在Go中实现一个轻量级的线程池。 #### 一、线程池的基本概念 在传统的多线程编程中,线程池是指维护一个可重复使用的线程集合,通过预先创建一定数量的线程,并将这些线程放入池中等待任务的到来。当任务到来时,线程池会从池中取出一个空闲线程来执行任务,任务执行完毕后,线程并不销毁,而是再次放回池中等待下一次任务的分配。这样做的好处是减少了线程的创建和销毁开销,提高了程序的执行效率。 在Go语言中,由于goroutine的轻量级特性(创建和销毁开销远小于传统线程),我们通常不直接使用“线程池”这一术语,而是通过goroutine和channel来实现类似的功能。我们可以设计一个任务队列,结合worker goroutine(工作goroutine)来模拟线程池的行为。 #### 二、实现轻量级线程池的步骤 1. **定义任务类型**:首先,我们需要定义一个任务类型,这通常是一个函数或结构体中包含的方法,表示需要在线程池中执行的任务。 2. **创建任务队列**:使用channel作为任务队列,其中存储待执行的任务。通常使用无缓冲或带缓冲的channel,根据具体需求决定。 3. **启动worker goroutine**:根据需求启动一定数量的worker goroutine,这些goroutine不断从任务队列中取出任务并执行。 4. **提交任务**:提供一个方法用于将任务提交到任务队列中,以便worker goroutine可以取出并执行。 5. **优雅关闭**:实现一个机制来优雅地关闭线程池,即等待所有正在执行的任务完成后,再退出worker goroutine。 #### 三、代码实现 下面是一个简单的轻量级线程池的实现示例: ```go package main import ( "fmt" "sync" "time" ) // Task 表示线程池中的任务 type Task func() // ThreadPool 结构体表示线程池 type ThreadPool struct { taskQueue chan Task // 任务队列 workerCount int // worker goroutine的数量 wg sync.WaitGroup // 等待所有worker完成 quit chan bool // 用于优雅关闭的信号 } // NewThreadPool 创建一个新的线程池 func NewThreadPool(workerCount int) *ThreadPool { return &ThreadPool{ taskQueue: make(chan Task, 100), // 可根据实际需要调整缓冲大小 workerCount: workerCount, quit: make(chan bool), } } // Start 启动线程池 func (tp *ThreadPool) Start() { for i := 0; i < tp.workerCount; i++ { tp.wg.Add(1) go tp.worker(i) } } // worker 是单个worker goroutine的工作函数 func (tp *ThreadPool) worker(workerID int) { defer tp.wg.Done() for { select { case task := <-tp.taskQueue: task() // 执行任务 case <-tp.quit: return // 收到退出信号,结束当前worker } } } // Submit 提交任务到线程池 func (tp *ThreadPool) Submit(task Task) { tp.taskQueue <- task } // Stop 优雅关闭线程池 func (tp *ThreadPool) Stop() { close(tp.quit) // 关闭quit channel,通知worker goroutine退出 tp.wg.Wait() // 等待所有worker完成 close(tp.taskQueue) // 关闭任务队列 } func main() { // 创建一个包含5个worker的线程池 tp := NewThreadPool(5) tp.Start() // 提交任务 for i := 0; i < 10; i++ { idx := i tp.Submit(func() { fmt.Printf("执行任务 %d\n", idx) time.Sleep(time.Second) // 模拟任务执行时间 }) } // 等待一定时间后,优雅关闭线程池 time.Sleep(3 * time.Second) tp.Stop() fmt.Println("线程池已关闭") } ``` #### 四、讨论与扩展 1. **任务队列的缓冲大小**:在上述示例中,任务队列`taskQueue`被设置为有缓冲的channel,这有助于在任务提交时不会因为队列满而阻塞。然而,缓冲大小的选择需要根据实际情况来确定,过大会占用过多内存,过小则可能频繁阻塞。 2. **优雅关闭**:通过`quit` channel和`sync.WaitGroup`实现了线程池的优雅关闭。确保在退出前所有任务都被执行完毕,这是多线程/goroutine编程中常见且重要的考虑点。 3. **错误处理**:上述示例中没有处理任务执行中可能出现的错误。在实际应用中,应该为任务定义一个返回错误类型的函数签名,并在worker中处理这些错误。 4. **动态调整worker数量**:当前的实现中worker数量是固定的。在一些复杂的应用场景中,可能需要根据系统负载动态调整worker的数量。这通常涉及到更复杂的并发控制和状态管理。 5. **性能调优**:根据实际应用场景对线程池的性能进行调优,比如调整worker数量、任务队列的缓冲大小等,以达到最优的并发性能。 通过以上步骤和代码示例,你应该已经能够理解并实现在Go语言中的轻量级线程池了。这种线程池的实现方式利用了Go语言强大的并发编程特性,通过goroutine和channel来实现高效的任务调度和执行。
上一篇:
34|并发:如何使用共享变量?
下一篇:
36|打稳根基:怎么实现一个TCP服务器?(上)
该分类下的相关小册推荐:
深入浅出Go语言核心编程(二)
WebRTC音视频开发实战
Go开发权威指南(下)
企业级Go应用开发从零开始
深入浅出Go语言核心编程(八)
深入浅出Go语言核心编程(三)
深入浅出Go语言核心编程(六)
深入浅出Go语言核心编程(五)
go编程权威指南(二)
Go Web编程(上)
深入浅出Go语言核心编程(七)
Go Web编程(下)