1.代理模式
- 可以用以下的例子來學習
- github.com/crazybber/go-pattern-ex...
2.執行緒生命週期(先看圖) — 瞭解執行緒的生命週期即可
- 執行緒狀態: 建立(new),就緒(runnable),執行(run),阻塞(block),結束(dead)
- www.cnblogs.com/sunddenly/p/410656...
3.go runtine
- 瞭解go runtine 中的執行狀態能幫助我們判斷輸出結果為什麼是稀奇古怪的
- blog.csdn.net/kojhliang/article/de...
4.死鎖,以及防止死鎖, sync.Mutex
- 死鎖四種條件: 互斥條件,請求與保持條件,不剝奪條件,迴圈等待條件
- zhuanlan.zhihu.com/p/61221667
- studygolang.com/pkgdoc
5.sync.WaitGroup 計數器
- 可以減少專案外使用 time.Sleep()
- studygolang.com/articles/12972
- 為了減少記憶體的重複呼叫
- 減少上下文切換時間
- 根據合適的場景運用池,不合適的場景用池反而會適得其反
- 由於go runtine 中的記憶體排程足夠好,不需要進行記憶體的分配
- 可以通過golang中限制 Goruntine的併發數,來限制記憶體排程
- segmentfault.com/a/119000001795639...
1.確定任務和池的引數
const (
STOPED = iota
RUNNING
)
// Task 任務
type Task struct {
//傳入函式
Handler func(v ...interface{})
//需要傳入的引數(v)
Params []interface{}
}
// Pool 池
type Pool struct {
//最大容量
MaxCap int
//正在進行的任務數量
active int
//池的狀態 RUNNING OR STOPED
status int
//任務通道
chTask chan *Task
//鎖
mu sync.Mutex
//用於等待一組執行緒的結束
wg sync.WaitGroup
}
2.根據代理模式和執行緒的生命週期建立函式
// NewPool 建立
func NewPool(maxCap int) (*Pool, error) {
return nil,nil
}
// Put 就緒
func (p *Pool) Put(task *Task) error {
return nil
}
// run 執行
func (p *Pool) run() {
}
//worker 阻塞
func (p *Pool) worker() {
}
// Close 結束
func (p *Pool) Close() {
}
3.填充內容
1.建立
// NewPool 建立
// 1.判斷容量是否合理
// 2.初始化池
func NewPool(maxCap int) (*Pool, error) {
if maxCap <= 0 {
return nil, errors.New("invalid pool cap")
}
return &Pool{
MaxCap: maxCap,
status: RUNNING,
chTask: make(chan *Task, maxCap),
}, nil
}
2.就緒
// Put 就緒
// 1.加鎖 --- 破壞迴圈等待條件
// 2.判斷池的狀態
// 3.放入訊息佇列
// 4.計數器+1
// 5.轉到執行態
func (p *Pool) Put(task *Task) error {
p.mu.Lock()
defer p.mu.Unlock()
if p.status == STOPED {
return ErrPoolAlreadyClosed
}
//放入訊息佇列中
p.chTask <- task
//計數器+1
p.wg.Add(1)
//執行執行緒
if p.active < p.MaxCap {
p.run()
}
return nil
}
3.執行
// run 執行
// 1.執行數+1
// 2.通過 go runtine 執行
func (p *Pool) run() {
p.active++
go p.worker()
}
4.阻塞
//worker 阻塞
// 1.消費通道中的任務 <-p.chTask
// select在channel為nil時會阻塞佇列
// 2.執行函式
// 3.活動數-1
// 4.減少WaitGroup計數器的值
func (p *Pool) worker() {
//延後執行
defer func() {
p.active--
p.wg.Done()
}()
for {
select {
case task, ok := <-p.chTask:
if !ok {
return
}
task.Handler(task.Params...)
}
}
}
5.關閉
// Close 結束
// 1.設定狀態為結束
// 2.關閉執行緒
// 3.阻塞直到WaitGroup計數器減為0
func (p *Pool) Close() {
p.status = STOPED
close(p.chTask)
p.wg.Wait()
}
4.測試
func TestPool(t *testing.T) {
t.Run("pool", func(t *testing.T) {
pool, err := NewPool(20)
defer pool.Close()
assert.Nil(t, err)
for i := 0; i < 20; i++ {
pool.Put(&Task{
Handler: func(v ...interface{}) {
fmt.Println(v)
},
Params: []interface{}{i},
})
}
})
}
segmentfault.com/a/119000002146835...
www.cnblogs.com/wongbingming/p/130...
geektutu.com/post/hpg-concurrency-...
本作品採用《CC 協議》,轉載必須註明作者和本文連結