goroutine和channel让go 多并发显得简单而且效率很高,本节主要针对协程和管道在不同的应用场景下的具体实现。
1. channel与interface结合,完成多态
type A interface {
Test()
}
type B struct{}
type C struct{}
func (b *B) Test() {
fmt.Println("B...")
}
func (c *C) Test() {
fmt.Println("C...")
}
func chanTest() {
//chan 与interface结合,完成多态
ch := make(chan A, 2)
b := new(B)
c := new(C)
ch <- b
ch <- c
close(ch)
for a := range ch {
a.Test()
}
}
输出结果如下:
B...
C...
Process finished with exit code 0
2. channel与func相结合
type A interface {
Test()
}
type B struct{}
type C struct{}
func (b *B) Test() {
fmt.Println("B...")
}
func (c *C) Test() {
fmt.Println("C...")
}
func chanTest() {
ch1 := make(chan func(), 2)
b := new(B)
c := new(C)
ch1 <- b.Test
ch1 <- c.Test
close(ch1)
for a := range ch1 {
a()
}
}
输出结果如下:
B...
C...
Process finished with exit code 0
3. channel传递数据的速度
测试1s通过管道完成多少数据的传递
func chanTest(){
ch := pump() //无限获取chan中的数据
go func() {
for {
if i, ok := <-ch; ok {
fmt.Println(i)
} else {
fmt.Println("break...")
break
}
}
}()
select {
case <-time.After(time.Second):
return
}
}
func pump() chan int {
ch := make(chan int)
go func() { //goroutine运行不会因为方法pump的结束而结束,等待主程序结束而结束
for i := 0; ; i++ {
ch <- i
}
}()
return ch
}
结果输出如下,完成了14万数据的传输:
4. 定时器和计时器
func chanTest(){
//定时器和计时器
tick := time.Tick(time.Second)
boom := time.After(5 * time.Second)
for {
select {
case <-tick:
fmt.Println("tick.")
case <-boom:
fmt.Println("BOOM!")
return
}
}
}
输出结果如下:
tick.
tick.
tick.
tick.
tick.
BOOM!
Process finished with exit code 0
- time.Afer():理解为计时器,等待一定时间,会向管道中发送信号,结束程序
- time.Tick():理解为定时器,每隔一定时间,定时向管道发送信号,执行某一操作,可以用来万层Cron任务
5. 生成器
每一次调用生成一个偶数值
func NewInteger() chan int {
ch := make(chan int)
go func() {
for i := 0; ; i++ {
ch <- i * 2
}
}()
return ch
}
func NextInteger(ch chan int) int {
return <-ch
}
func generateTest() {
next := NewInteger()
for {
fmt.Println(NextInteger(next))
time.Sleep(time.Second)
}
}
结果如下:
6. recover 完成try-catch操作
go语言中没有try-catch语句,但是可以通过recover来操作panic报错
func chanAndRecover() {
ch := make(chan int)
go func() {
for i := 0; i < 5; i++ {
ch <- i
}
}()
for i := 0; i < 5; i++ {
go func(i int) {
//如果不加recover来处理panic,一旦一个goroutine发生错误,会影响其他goroutine执行
defer func() {
if err := recover(); err != nil { //catch操作
log.Println("Error:", i)
}
}()
fmt.Println(i, 10/i)
}(<-ch)
}
time.Sleep(2 * time.Second)
}
结果输出:
1 10
3 3
2 5
4 2
2020/12/14 17:12:48 Error: 0
Process finished with exit code 0
7. Future
多种操作之间没有相互依赖关系,可以并行执行
func futuresTest(a, b int) {
// old type,计算a1与b1之间没有任何关系,可以并行执行
start := time.Now()
a1 := oldCompute(a)
b1 := oldCompute(b)
allTime := time.Since(start).Nanoseconds()
fmt.Printf("time=%d,result=%d\n", allTime, a1*b1)
// new type
start = time.Now()
cha := newCompute(a)
chb := newCompute(b)
allTime = time.Since(start).Nanoseconds()
fmt.Printf("time=%d,result=%d\n", allTime, <-cha*<-chb)
}
输出耗时如下:
time=2000859200,result=400000000
time=0,result=400000000
Process finished with exit code 0
8. 模拟连接池
9. 控制访问次数
10. 更多
后期再补充