Skip to content

Commit 59a1041

Browse files
committed
Add:新增文章<如何实现一个协程池>
1 parent aa497c4 commit 59a1041

File tree

5 files changed

+79
-21
lines changed

5 files changed

+79
-21
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
- 4.6 [学习 Go 协程:互斥锁和读写锁](http://golang.iswbm.com/en/latest/c04/c04_06.html)
4444
- 4.8 [学习一些常见的并发模型](http://golang.iswbm.com/en/latest/c04/c04_08.html)
4545
- 4.9 [理解 Go 语言中的 Context](http://golang.iswbm.com/en/latest/c04/c04_09.html)
46-
- 4.10 [函数式编程](http://golang.iswbm.com/en/latest/c04/c04_10.html)
46+
- 4.10 [如何实现一个协程池?](http://golang.iswbm.com/en/latest/c04/c04_10.html)
4747

4848
## 第五章:Web实战
4949
- 5.1 [Gin 实战:Hello World](http://golang.iswbm.com/en/latest/c05/c05_01.html)

source/c04/c04_09.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
## 1. 什么是 Context?
44

5-
go 1.7 版本之前,context 还是非编制的,它存在于 golang.org/x/net/context 包中。
5+
Go 1.7 版本之前,context 还是非编制的,它存在于 golang.org/x/net/context 包中。
66

7-
后来,golang 团队发现 context 还挺好用的,就把 context 收编了,在 go 1.7 版本正式纳入了标准库。
7+
后来,Golang 团队发现 context 还挺好用的,就把 context 收编了,在 Go 1.7 版本正式纳入了标准库。
88

99
Context,也叫上下文,它的接口定义如下
1010

@@ -74,7 +74,7 @@ func main() {
7474

7575
> chan+select的方式,是比较优雅的结束一个goroutine的方式,不过这种方式也有局限性,如果有很多goroutine都需要控制结束怎么办呢?如果这些goroutine又衍生了其他更多的goroutine怎么办呢?如果一层层的无穷尽的goroutine呢?这就非常复杂了,即使我们定义很多chan也很难解决这个问题,因为goroutine的关系链就导致了这种场景非常复杂。
7676
77-
在这里我不是很赞同他说的话,因为我觉得就算只使用一个通道也能控制(取消)多个 goroutine 的目的。下面就用例子来验证一下。
77+
在这里我不是很赞同他说的话,因为我觉得就算只使用一个通道也能达到控制(取消)多个 goroutine 的目的。下面就用例子来验证一下。
7878

7979
该例子的原理是:使用 close 关闭通道后,如果该通道是无缓冲的,则它会从原来的阻塞变成非阻塞,也就是可读的,只不过读到的会一直是零值,因此根据这个特性就可以判断 拥有该通道的 goroutine 是否要关闭。
8080

@@ -235,7 +235,7 @@ cancel()
235235

236236
创建 Context 必须要指定一个 父 Context,当我们要创建第一个Context时该怎么办呢?
237237

238-
不用担心,Go 已经帮我们实现了2个,我们代码中最开始都是以这两个内置的作为最顶层的partent context,衍生出更多的子Context。
238+
不用担心,Go 已经帮我们实现了2个,我们代码中最开始都是以这两个内置的context作为最顶层的parent context,衍生出更多的子Context。
239239

240240
```go
241241
var (

source/c04/c04_09.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
1. 什么是 Context?
55
-------------------
66

7-
go 1.7 版本之前,context 还是非编制的,它存在于
7+
Go 1.7 版本之前,context 还是非编制的,它存在于
88
golang.org/x/net/context 包中。
99

10-
后来,golang 团队发现 context 还挺好用的,就把 context 收编了,在 go 1.7
10+
后来,Golang 团队发现 context 还挺好用的,就把 context 收编了,在 Go 1.7
1111
版本正式纳入了标准库。
1212

1313
Context,也叫上下文,它的接口定义如下
@@ -87,7 +87,7 @@ Context,也叫上下文,它的接口定义如下
8787

8888
chan+select的方式,是比较优雅的结束一个goroutine的方式,不过这种方式也有局限性,如果有很多goroutine都需要控制结束怎么办呢?如果这些goroutine又衍生了其他更多的goroutine怎么办呢?如果一层层的无穷尽的goroutine呢?这就非常复杂了,即使我们定义很多chan也很难解决这个问题,因为goroutine的关系链就导致了这种场景非常复杂。
8989

90-
在这里我不是很赞同他说的话,因为我觉得就算只使用一个通道也能控制(取消)多个
90+
在这里我不是很赞同他说的话,因为我觉得就算只使用一个通道也能达到控制(取消)多个
9191
goroutine 的目的。下面就用例子来验证一下。
9292

9393
该例子的原理是:使用 close
@@ -261,7 +261,7 @@ cancel 就是我们在创建 ctx 的时候返回的第二个值。
261261
Context,当我们要创建第一个Context时该怎么办呢?
262262

263263
不用担心,Go
264-
已经帮我们实现了2个,我们代码中最开始都是以这两个内置的作为最顶层的partent
264+
已经帮我们实现了2个,我们代码中最开始都是以这两个内置的context作为最顶层的parent
265265
context,衍生出更多的子Context。
266266

267267
.. code:: go

source/c04/c04_10.md

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,40 @@
1-
# 4.10 函数式编程
1+
# 4.10 如何实现一个协程池?
22

3-
函数是一等公民,它可以做为参数进行传递,可以做为函数返回值,也可以做为接收者。所以后来才有了高阶函数,闭包。
3+
协程池的实现
44

5+
```go
6+
type Pool struct {
7+
work chan func() // 任务 sem chan struct{} // 数量
8+
}
9+
func New(size int) *Pool {
10+
return &Pool{
11+
work: make(chan func()),
12+
sem: make(chan struct{}, size),
13+
}
14+
}
15+
func (p *Pool) Schedule(task func()) error { // 任务调度
16+
select {
17+
case p.work <- task:
18+
case p.sem <- struct{}{}:
19+
go p.worker(task)
20+
}
21+
}
22+
func (p *Pool) worker(task func()) { // 任务执行
23+
defer func() { <-p.sem }
24+
for {
25+
task()
26+
task = <-p.work
27+
}
28+
}
529

30+
```
631

7-
正统的函数式编程
8-
9-
- 不可变性:不能有状态,只能有函数和变量
10-
- 函数只能有一个参数
32+
协程池的调用
1133

34+
```go
35+
pool := gopool.New(128)
36+
pool.Schedule(func(){
37+
fmt.println("task run")
38+
})
39+
```
1240

source/c04/c04_10.rst

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,39 @@
1-
4.10 函数式编程
2-
===============
1+
4.10 如何实现一个协程池?
2+
=========================
33

4-
函数是一等公民,它可以做为参数进行传递,可以做为函数返回值,也可以做为接收者。所以后来才有了高阶函数,闭包。
4+
协程池的实现
55

6-
正统的函数式编程
6+
.. code:: go
77
8-
- 不可变性:不能有状态,只能有函数和变量
9-
- 函数只能有一个参数
8+
type Pool struct {
9+
work chan func() // 任务 sem chan struct{} // 数量
10+
}
11+
func New(size int) *Pool {
12+
return &Pool{
13+
work: make(chan func()),
14+
sem: make(chan struct{}, size),
15+
}
16+
}
17+
func (p *Pool) Schedule(task func()) error { // 任务调度
18+
select {
19+
case p.work <- task:
20+
case p.sem <- struct{}{}:
21+
go p.worker(task)
22+
}
23+
}
24+
func (p *Pool) worker(task func()) { // 任务执行
25+
defer func() { <-p.sem }
26+
for {
27+
task()
28+
task = <-p.work
29+
}
30+
}
31+
32+
协程池的调用
33+
34+
.. code:: go
35+
36+
pool := gopool.New(128)
37+
pool.Schedule(func(){
38+
fmt.println("task run")
39+
})

0 commit comments

Comments
 (0)