golang 简单连接池

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package main
  
import (
    "fmt"
    "time"
)
  
/* 有关Task任务相关定义及操作 */
//定义任务Task类型,每一个任务Task都可以抽象成一个函数
type Task struct {
    f func() error //一个无参的函数类型
}
  
//通过NewTask来创建一个Task
func NewTask(f func() error) *Task {
    t := Task{
        f: f,
    }
    return &t
}
  
//执行Task任务的方法
func (t *Task) Execute() {
    t.f() //调用任务所绑定的函数
}
  
/* 有关协程池的定义及操作 */
//定义池类型
type Pool struct {
    EntryChannel chan *Task //对外接收Task的入口
    worker_num   int        //协程池最大worker数量,限定Goroutine的个数
    JobsChannel  chan *Task //协程池内部的任务就绪队列
}
  
//创建一个协程池
func NewPool(cap int) *Pool {
    p := Pool{
        EntryChannel: make(chan *Task),
        worker_num:   cap,
        JobsChannel:  make(chan *Task),
    }
    return &p
}
  
//协程池创建一个worker并且开始工作
func (p *Pool) worker(work_ID int) {
    //worker不断的从JobsChannel内部任务队列中拿任务
    for task := range p.JobsChannel {
        //如果拿到任务,则执行task任务
        task.Execute()
        fmt.Println("worker ID ", work_ID, " 执行完毕任务")
    }
}
  
//让协程池Pool开始工作
func (p *Pool) Run() {
    //1,首先根据协程池的worker数量限定,开启固定数量的Worker,
    //  每一个Worker用一个Goroutine承载
    for i := 0; i < p.worker_num; i++ {
        fmt.Println("开启固定数量的Worker:", i)
        go p.worker(i)
    }
  
    //2, 从EntryChannel协程池入口取外界传递过来的任务
    //   并且将任务送进JobsChannel中
    for task := range p.EntryChannel {
        p.JobsChannel <- task
    }
  
    //3, 执行完毕需要关闭JobsChannel
    close(p.JobsChannel)
    fmt.Println("执行完毕需要关闭JobsChannel")
  
    //4, 执行完毕需要关闭EntryChannel
    close(p.EntryChannel)
    fmt.Println("执行完毕需要关闭EntryChannel")
}
  
//主函数
func main() {
    //创建一个Task
    t := NewTask(func() error {
        fmt.Println("创建一个Task:", time.Now().Format("2006-01-02 15:04:05"))
        return nil
    })
  
    //创建一个协程池,最大开启3个协程worker
    p := NewPool(3)
  
    //开一个协程 不断的向 Pool 输送打印一条时间的task任务
    go func() {
        for {
            p.EntryChannel <- t
        }
    }()
  
    //启动协程池p
    p.Run()
}

  

动态版(待完善)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package main
 
import (
    "fmt"
    "sync"
    "time"
)
 
type Task struct {
    f func()
}
 
func NewTask(f func()) Task {
    return Task{
        f: f,
    }
}
 
type Work struct {
    status    int
    closeChan chan struct{}
}
 
func NewWork() *Work {
    return &Work{
        status:    0,
        closeChan: make(chan struct{}),
    }
}
 
func (w *Work) work(job chan Task, wg *sync.WaitGroup) {
 
    ticker := time.NewTicker(3 * time.Second)
    //定时查询自己
    for {
        select {
        case <-w.closeChan:
            //判断当前最小值
            wg.Done()
            break
        case task := <-job:
            w.status = 1
            task.f()
        case <-ticker.C:
            w.status = 0
            ticker.Reset(3 * time.Second)
        }
    }
}
 
type Pool struct {
    Max     int
    Min     int
    JobChan chan Task
    Workers []*Work
}
 
func NewPoll(max, min int) *Pool {
    return &Pool{
        Max:     max,
        Min:     min,
        JobChan: make(chan Task),
        Workers: make([]*Work, 0),
    }
}
 
func (p *Pool) Submit(t Task) {
    p.JobChan <- t
}
 
func (p *Pool) Run() {
 
    var wg sync.WaitGroup
 
    for i := 0; i < p.Min; i++ {
        // go NewWork().work(p.JobChan, &wg)
        p.Workers = append(p.Workers, NewWork())
    }
 
    p.Schdule(&wg)
    fmt.Println("11111111")
    p.Watch(&wg)
    wg.Wait()
}
 
func (p *Pool) Schdule(wg *sync.WaitGroup) {
    for j := 0; j < len(p.Workers); j++ {
        if p.Workers[j].status == 0 {
            wg.Add(1)
            go p.Workers[j].work(p.JobChan, wg)
        }
    }
}
 
// 监控worker
func (p *Pool) Watch(wg *sync.WaitGroup) {
    fmt.Println("watch")
    //TODO 监控work数 小于最大数,且持续5秒没完成,则创建新worker
    for {
        ticker := time.NewTicker(5 * time.Second)
        select {
        case <-ticker.C:
            fmt.Println("timeeeeeeeeeeee")
            for _, v := range p.Workers {
                if v.status == 0 && len(p.Workers) > p.Min {
                    //关闭worker
                    close(v.closeChan)
                }
            }
 
            if len(p.Workers) < p.Max && len(p.Workers) >= p.Min {
                p.Workers = append(p.Workers, NewWork())
                p.Schdule(wg)
            }
            ticker.Reset(5 * time.Second)
        }
    }
}
 
func main() {
    p := NewPoll(10, 3)
 
    go func() {
        for {
            p.Submit(NewTask(func() {
                // fmt.Println(time.Now().Format("2006-01-02 15:04:05"))
            }))
        }
    }()
 
    go func() {
        for {
            time.Sleep(time.Second)
            fmt.Println(len(p.Workers))
        }
 
    }()
 
    p.Run()
}

  

 

参考链接:https://blog.csdn.net/finghting321/article/details/106492915/

 

posted @   GPHPER  阅读(72)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
TOP
点击右上角即可分享
微信分享提示