您的位置:

Go语言线程池详解

一、Go线程池和并发

Go语言中并发通过Goroutine来实现,每个Goroutine都相当于一个轻量级线程,可以通过go关键字创建。在需要处理并发问题时,我们可以通过创建多个Goroutine来实现。但是如果创建的Goroutine过多,会消耗过多的系统资源,导致系统运行缓慢甚至崩溃。

线程池是一种常用的并发处理机制,它可以在一定范围内控制线程的数量,避免过多的线程导致系统崩溃。Go语言中也提供了线程池的实现。线程池包含了固定数量的线程,可以通过提交任务来让线程执行,执行完毕后线程会自动回收,而不会占用系统资源。

二、Go线程池参数

在使用线程池时,我们需要了解一些常见的线程池参数,以便更好地实现我们的需求:

  • 最小线程数:线程池中保持的最小线程数。
  • 最大线程数:线程池中允许的最大线程数。
  • 任务队列:用于存储等待执行的任务。
  • 拒绝策略:当线程池达到最大线程数并且任务队列已满时,用于处理新的任务。

三、线程池原理

线程池的原理是通过一个任务队列来存储等待执行的任务。当任务队列中有任务时,线程池中的线程会从队列中取出任务执行。如果线程数已达到最大值,新的任务将会被放入任务队列等待执行。当线程池中的线程空闲时,它们会定期从任务队列中取出任务执行。

一般来说,线程池的实现可分为两种方式:基于固定数量的线程池和基于可伸缩数量的线程池。在Go语言中,一般采用基于可伸缩数量的线程池实现。

四、Go语言线程池

Go语言中内置了线程池的实现,可以简单地通过包管理器下载使用。下面是一个基于Go语言内置线程池的例子:

package main

import (
    "fmt"
    "sync"
)

func work(i int) {
    fmt.Println(i)
}

func main() {
    size := 10
    jobs := make(chan int, size)
    var wg sync.WaitGroup
    for i := 0;i < size;i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for j := range jobs {
                work(j)
            }
        }()
    }
    for i := 0;i < size;i++ {
        jobs <- i
    }
    close(jobs)
    wg.Wait()
}

五、线程池的拒绝策略

当线程池中的线程数已达到最大值并且任务队列已满时,我们需要采取一些策略来拒绝新的任务,以免影响系统的正常运行。线程池的拒绝策略主要有以下几种:

  • AbortPolicy(默认策略):直接抛出RejectedExecutionException异常。
  • CallerRunsPolicy:由提交任务的线程去执行任务。这样做会降低系统的吞吐量,但可以避免任务的丢失。
  • DiscardOldestPolicy:将等待时间最久的任务丢弃,尝试添加新的任务到任务队列中。
  • DiscardPolicy:直接丢弃新的任务。

六、C++线程池

相比Go语言内置的线程池,C++并没有提供类似的实现。不过我们可以使用第三方库来实现线程池。

在C++中,一个比较常用的线程池库是ThreadPool。下面是一个基于ThreadPool库的例子,需要通过包管理器下载和安装ThreadPool。

#include 
#include "ThreadPool.h"

void work(int i) {
    std::cout << i << std::endl;
}

int main() {
    int size = 10;
    thread_pool::ThreadPool pool(size);
    for (int i = 0;i < size;i++) {
        pool.enqueue([i]() {
            work(i);
        });
    }
    return 0;
}

  

七、线程池shutdown

线程池的shutdown方法用于关闭线程池。调用shutdown方法后,线程池将不再接受新的任务,并且会等待所有任务都执行完毕后关闭线程池。

在Go语言中,使用Close方法可以关闭线程池。

在C++中,使用ThreadPool的stop方法可以关闭线程池。

八、Hutool线程池

Hutool是一个Java工具包,内置了线程池的实现。下面是一个基于Hutool的例子,需要下载和导入Hutool:

import cn.hutool.core.thread.ThreadExecutor;
import cn.hutool.core.thread.ThreadFactoryBuilder;

public class ThreadPoolTest {
    public static void main(String[] args) {
        int size = 10;
        ThreadExecutor executor = new ThreadExecutor(size, size, 60, 
                                      new ArrayBlockingQueue(size), 
                                      new ThreadFactoryBuilder().setNamePrefix("test").build(), 
                                      new ThreadPoolExecutor.AbortPolicy());
        for (int i = 0;i < size;i++) {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    work(i);
                }
            });
        }
        executor.shutdown();
    }
    public static void work(int i) {
        System.out.println(i);
    }
}

  

九、Boost线程池

Boost是一个C++库,在其中集成了线程池的实现。下面是一个基于Boost的例子,需要下载和导入Boost库:

#include 
#include 
   
#include 
    

void work(int i) {
    std::cout << i << std::endl;
}

int main() {
    int size = 10;
    boost::thread_pool::pool pool(size);
    for (int i = 0;i < size;i++) {
        pool.submit(boost::bind(work, i));
    }
    pool.join();
    return 0;
}

    
   
  
以上对线程池和Go语言线程池的介绍,相信可以对大家在实际编程工作中的开发有所帮助。感谢大家阅读!