线程池的实现

Golang 线程池

线程其实就是协程,但是还是说线程吧,习惯了

线程池最经典的demo感觉莫过于Java 的ThreadPool了,写得真的非常棒,过段时间要回顾下了,借鉴下

核心就是以下几点(暂时想到的):

  • 有一个统一的分发类,也可以认为是池主体
  • 池具体的对象

用Go来演示就是这样:


var JobQueue chan interface{}
type Worker interface {
	io.Closer
	Consume()
}

type BaseDispatcher struct {
	workPool chan chan interface{}
	workers    []Worker // 保存了哪些worker
}


type PacketWorker struct {
	workPool chan chan gopacket.Packet
	jobQueue chan gopacket.Packet
}

核心方法:
func (d *Dispatcher) dispatch() {
    for {
        select {
        case job := <-JobQueue:
             go func(job Job) {
                jobChannel := <-d.workPool
                jobChannel <- job
            }(job)
        }
    }
}

func (w *PacketWorker) Start() {
	for {
		w.workQueue <- w.jobQueue
		select {
		case job := <-w.jobQueue:
			w.Consume(job)
		
		}
	}
}

可以认为有3个角色: job ,worker ,dispatcher

  • job 毫无疑问:只是一个对象,内部则是处理的数据
  • worker则是处理job的执行者
  • dispatcher是分发任务,所有的生成的任务job,都会通过dispatcher入队到工作队列中
    可能会有以下疑问:
  1. 为什么worker对象也要持有workPool的引用
  2. 为什么Dispatcher要持有所有worker的引用
  3. 为什么是chan chan类型
  4. 为什么会有一个JobQueue
  5. 为什么dispatch 方法是for 循环中创建线程,而不是有专门的几个线程分发任务
  6. dispatcher是如何做到分发的

答:

  1. 可以认为是永动机,而永动机形成就是通过这个持有引用形成的,当这个worker执行完毕他自己的jobQueue中的任务之后,就会跳出select,从而会重新入线程池,告诉dispatcher我的任务已经执行完毕了,并且此时这个worker会被自己的jobQueue阻塞,当重新入队之后,有任务来了,disaptcher就会出队一个jobQueue,某个worker持有这个引用,从而继续执行,所以这就是永动机,总结就是拿来收发任务的
  2. 线程通常都会携带某种资源,既占据内存,当线程结束总要释放资源,这个作用就是如此:对worker对象生命周期的管理
  3. 因为go中线程很廉价,但是廉价也不是随意乱用,这个的作用是起缓冲的作用
  4. 很简单,这个是作为一个中间者的,类似于交通工具上的卡车,用于传输数据,不然得到了数据怎么将其添加然后分发给worker工作呢
    4.1 可能有新的疑问: 为什么只有一个JobQueue来接收数据,而不是多JobQueue来充当传输呢
    答: 多个JobQueue无非就是当Job太多时,consumer速度跟不上producer速度,但是其实我们可以折中的,注意内部的element是interface{}不是具体的类型,也就意味着我们producer 可以做缓存,当缓存满的时候再入队,这是非常可取的,如果真的想创建多个JobQueue的话,不如将时间优化放在consumer上,当consumer时间开销小了,自然这个JobQueue1个也够了
  5. 这点其实就是Go有别于其他编程语言,如Java了,Java线程开销昂贵,Go却是很轻松,在Java中这样是不可取的
  6. dispatcher有一个自己的线程,基本上属于一个死循环,一旦JobQueue有任务来了,就会从线程池中出队一个worker(这点在Java中是通过数组实现的),这个worker不是真正的worker,而是被真正的worker所引用的一个存放job的通道,真正的worker也会是死循环,因为持有引用,所以当这个chan被添加任务之后,那worker也感知到了,就能消费了,当这个worker消费完毕之后,这个worker所持有的jobQueue又会重新入队,并且是非阻塞的,因为当我们初始化的时候是会指定workQueue的len的,并且当达到len的时候也没关系(这时候所有的worker都是阻塞在自身的jobQueue中的,因为都已经入workQueue了),当来新的job的时候(a这个jobQueue出队),对应的worker持有引用,消费完毕之后重新入队,就跟永动机一样

2019-01-05 22:30 有空再更,做项目

2019-01-07 23:23 更

  • 今天突然想到一点,应该只有我自己能看懂了,就是当worker的jobQueue出队的时候代表着是有新的任务来了(来了新的任务就会出队),然后这个worker持有引用就是进行消费)这点其实与上面的一点是一致的

延伸

  • 上面的模式又可以称为并行流水线模式这个模式其实是与Java中的CountDownLatch有类似的关系,都是分发任务
    在这里插入图片描述

  • 与之对应的则有:多个数据发给一个接收者,这种模式又与Java中的CyclicBarrier类似,都是用于数据采集的(注意:这里是数据结构采集,不是耗时的工作,都是总结的功能,这点与上面是不同的,上面的为耗时的工作分发给worker)
    在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值