在Go中要实现高并发,可以使用 go routine 每个请求 都开启 一个 go routine 去处理,但这样的方式 当 流量大了 就不太可行了,另一种方法 是开启 一个 channel 缓存请求队列 然后 再 for select 循环去 取 任务 ,但是当 请求速度 达到最大 的channel 的时候 请求 就会阻塞, 所以 另一种 方法是结合 上面的2中有点 开启多个channel 每个channel 有一个 携程 去消化 ,这样 又可以利用多核的优势,用能控制携程 的数量。
package pool
import (
"fmt"
"sync"
)
//用于保存 的携程池
// 将实现 Job 接口的任务 扔到 任务池里
type Job interface {
Do() error
}
type myjob struct {}
func(mj *myjob) Do() error{
fmt.Println("asdasdasds")
return nil
}
type JobChan chan Job
type Workerchan chan JobChan
var(
//Worker 数量
MaxWorkerPoolSize = 100
)
type Worker struct {
WorkerPool Workerchan
JobChannel JobChan
quit chan bool
}
func NewWorker(workerPool Workerchan) *Worker {
//worker 自己注册一个管道
return &Worker{JobChannel: make(chan Job,512),WorkerPool:workerPool}
}
//启动一个Worker
func (w *Worker) Start(){
go func() {
for{
//注册自己的工作 管道 到全局任务管道中
w.WorkerPool <- w.JobChannel
select{
//从自己管道 中获取任务
case job := <- w.JobChannel:
//执行任务
if err := job.Do();err != nil{
fmt.Printf("excute job failed with err: %v", err)
}
//接收退出型号
case <-w.quit:
//如果管道中 还有未完成的任务 等待完成后 退出
if len(w.JobChannel) ==0 {
return
}
w.quit <- true
continue
}
}
}()
}
//停止Worker
func (w Worker) Stop() {
go func() {
w.quit <- true
}()
}
//分发器
type Dispatcher struct {
jobs JobChan
workPool Workerchan
Workers []*Worker
quit chan bool
}
func NewDispatcher(size int) *Dispatcher {
return &Dispatcher{workPool: make(chan JobChan,MaxWorkerPoolSize), quit: make(chan bool,1),jobs: make(JobChan,size)}
}
//退出
func(d *Dispatcher) Close(){
d.quit <- true
}
func(d *Dispatcher) Run(){
//新建 一定数量的消费者WOrker
for i:=0;i<MaxWorkerPoolSize;i++{
worker := NewWorker(d.workPool)
d.Workers = append(d.Workers, worker)
worker.Start()
}
go d.dispatch()
}
func(d *Dispatcher) Apply(job Job){
d.jobs <- job
}
func (d *Dispatcher) dispatch() {
for{
select{
//取出任务
case job := <- d.jobs:
go func(job Job) {
//如果有空闲的worker 可以处理请求
jobChan := <-d.workPool
//放入任务 让Worker 处理
jobChan <- job
}(job)
//接收退出
case <-d.quit:
//遍历所有Worker 停止工作
for _,v := range d.Workers{
v.Stop()
}
return
}
}
}
func main(){
wg := sync.WaitGroup{}
wg.Add(1)
b := NewDispatcher(1024)
b.Run()
//新建 一定数量的 任务 存入 临时存放任务的管道 再分配给 各个Worker
for i:=0;i<1000000;i++{
m := myjob{}
b.Apply(&m)
}
wg.Wait()
}