1. 让函数返回一个服务
概念理解
随机数生成器示例
func main() {
randCh := randGenService()
fmt.Println(<-randCh)
}
func randGenService() chan int {
randCh := make(chan int)
go func() {
for {
randCh <- rand.Int()
}
}()
return randCh
}
2. 多路复用
概念理解
增强版随机数生成器实例
func main() {
randCh := multiRandGenService()
fmt.Println(<-randCh)
}
func multiRandGenService() chan int {
gen1 := randGenService()
gen2 := randGenService()
randCh := make(chan int,2)
go func() {
select {
case r := <-gen1:
randCh <- r
case r := <-gen2:
randCh <- r
}
}()
return randCh
}
func randGenService() chan int {
randCh := make(chan int)
go func() {
for {
randCh <- rand.Int()
}
}()
return randCh
}
3. Future技术
概念理解
Future等于协程加上阻塞队列,阻塞队列用来接收一些未来可能传入的值,或输出的值.
- 我们可以在使用线程的时候,可以创建一个线程,返回Future,之后可以通过它等待线程结果
-
调用一个函数的时候,一般是参数已经准备好了。调用协程的时候也同样如此。但是如果我们将传入的参数设为通道,这样我们就可以在不准备好参数的情况下调用函数。这样的设计可以提供很大的自由度和并发度。函数调用和函数参数准备这两个过程可以完全解耦
数据库查询应用实例
type query struct {
in chan string //参数通道
out chan string //结果通道
}
func main() {
q := query{
in: make(chan string, 1),
out: make(chan string, 1),
}
queryDB(q)
q.in <- "select * from com_user"
fmt.Println(<-q.out)
}
func queryDB(q query) {
go func() {
in := <-q.in
q.out <- "get " + in
}()
}
4. 并发循环
概念理解
如果能让循环体并发执行,那么性能就会提高很多
代码示例
func main() {
c := []int{1, 2, 3, 4, 5, 6, 7}
wg := sync.WaitGroup{}
for _, i := range c {
doSomething(&wg, i) //注意只能使用方法调用,要不然会出现协程相互干扰的问题
}
wg.Wait()
fmt.Println("main :done")
}
func doSomething(wg *sync.WaitGroup, i int) {
wg.Add(1)
go func() {
defer wg.Done()
fmt.Printf("%s%d\n", "go :", i)
}()
}
5. chainfilter
概念理解
Future 输入输出首位相连,形成一个pipe。
示例—产生素数
func main() {
preGen := numGen()
for i := 0; i < 10; i++ {
prime := <- preGen
preGen = primeFilter(preGen,prime)
fmt.Println(prime)
}
}
func primeFilter(in <-chan int, prime int) chan int {
out := make(chan int)
go func() {
for { //注意该循环,要不停的从输入管道获取数据,然后写入输出
if i := <-in;i%prime!=0 {
out <- i
}
}
}()
return out
}
//数据源
func numGen() chan int {
ch := make(chan int)
go func() {
for i := 2;;i++ {
ch <- i
}
}()
return ch
}
6. 共享变量
用通道来模拟共享变量
示例代码
type shareVar struct {
in chan int
out chan int
}
func main() {
v := shareVar{
in: make(chan int),
out: make(chan int),
}
maintainShareVar(&v)
v.in <- 10
fmt.Println(<-v.out)
}
func maintainShareVar(v *shareVar) {
go func() {
var i int
for {
select {
case i = <-v.in:
case v.out <- i:
}
}
}()
}
7. 协程泄露问题处理
7.1 读通道协程泄露
加入定时器协程,用来同时读取事件
示例代码
func main() {
ch := make(chan int)
go rutineLeak(ch)
time.Sleep(time.Second*3)
fmt.Println("main done")
}
func rutineLeak(ch chan int) {
timeout := make(chan int)
go func() { //定时器协程
time.Sleep(time.Second*2)
timeout <- 0
}()
select {
case <-timeout:
case <-ch:
}
fmt.Println("I'am done")
}
7.2 写通道协程泄露
可指定通道的缓冲大小来解决