Go by Example 中文练习
Posted Parker@1989
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go by Example 中文练习相关的知识,希望对你有一定的参考价值。
文章目录
通道同步
func worker(done chan bool)
fmt.Println("working...")
time.Sleep(2 * time.Second)
fmt.Println("done")
done <- true
func main()
done := make(chan bool, 1)
go worker(done)
<-done
结果:
working...
done
[Finished in 3.1s]
通道选择
import (
"fmt"
"time"
)
func main()
ch1 := make(chan string, 1)
ch2 := make(chan string, 2)
go func()
time.Sleep(time.Second * 2)
ch1 <- "one"
()
go func()
time.Sleep(time.Second)
ch2 <- "two"
()
select
case msg1 := <-ch1:
fmt.Println(msg1)
case msg2 := <-ch2:
fmt.Println(msg2)
结果:
$ go run main.go
two
超时处理
func main()
ch1 := make(chan string, 1)
go func()
time.Sleep(time.Second * 1)
ch1 <- "1"
()
select
case res := <-ch1:
fmt.Println(res)
case <-time.After(time.Second * 1):
fmt.Println("time out 1")
ch2 := make(chan string, 1)
go func()
time.Sleep(time.Second * 2)
ch2 <- "2"
()
select
case res := <-ch1:
fmt.Println(res)
case <-time.After(time.Second * 1):
fmt.Println("time out 2")
结果:
$ go run main.go
1
time out 1
非阻塞通道
func main()
message := make(chan string)
select
case msg := <-message:
fmt.Print("message", msg)
default:
fmt.Println("no message receive")
msg := "1"
select
case message <- msg: // 当message通道定义一个缓冲区的时候,这里可以执行
fmt.Println("sent message")
default:
fmt.Println("no message sent")
结果
$ go run main.go
no message receive
no message sent
通道关闭
func main()
jobs := make(chan int, 5)
done := make(chan bool)
go func()
for
j, ok := <-jobs
if ok
fmt.Println("receive job ", j)
else
fmt.Println("receive all jobs")
done <- true // 通知主程序,已经接受全部任务
return
()
for i := 1; i < 3; i++
jobs <- i
fmt.Println("send job", i)
close(jobs)
fmt.Println("send all jobs")
<-done //等待通知
结果
$ go run main.go
send job 1
send job 2
send all jobs
receive job 1
receive job 2
receive all jobs
遍历通道
func main()
queue := make(chan string, 3)
queue <- "one"
queue <- "two"
close(queue)
for elem := range queue
fmt.Println(elem)
结果:
$ go run main.go
one
two
定时器
func main()
timer1 := time.NewTimer(time.Second * 2)
<-timer1.C
fmt.Println("timer 1 expired")
timer2 := time.NewTimer(time.Second * 2)
<-timer2.C
fmt.Println("timer 2 expired")
stop2 := timer2.Stop() // 此时timer2已经倒计时结束了,所以不需要停止
fmt.Println("stop2:", stop2)
if stop2
fmt.Println("timer 2 stoped")
结果:
$ go run main.go
timer 1 expired
timer 2 expired
stop2: false
上面例子中,因为timer2的倒计时已经停止,timer2.stop()没有执行,返回为false,如果想看停止效果,可以改写代码:
func main()
timer1 := time.NewTimer(time.Second * 2)
<-timer1.C
fmt.Println("timer 1 expired")
timer2 := time.NewTimer(time.Second * 5)
go func()
<-timer2.C
fmt.Println("timer 2 expired")
()
stop2 := timer2.Stop()
fmt.Println("stop2:", stop2)
if stop2
fmt.Println("timer 2 stoped")
结果:
$ go run main.go
timer 1 expired
stop2: true
timer 2 stoped
可以看到stop2停止了计时器,程序直接退出了。
也可以使用time自带的after方法实现
func main()
ch := make(chan string)
go func()
time.Sleep(time.Second * 2)
ch <- "result"
()
select
case res := <-ch:
fmt.Println(res)
case <-time.After(time.Second * 1):
fmt.Println("timeout")
结果:
$ go run main.go
timeout
计时器
Ticker和timer的区别是,timer倒计时到某一个时间点发送一个信号,而ticker是每隔多长时间发送一个信息,直到我们手动stop
func main()
ticker := time.NewTicker(time.Second)
go func()
for t := range ticker.C
fmt.Println("Tick at ", t)
()
time.Sleep(time.Second * 5)
ticker.Stop()
fmt.Println("ticker stopped")
结果:
$ go run main.go
Tick at 2021-05-20 08:55:17.817703 +0800 CST m=+1.003478727
Tick at 2021-05-20 08:55:18.819047 +0800 CST m=+2.004844288
Tick at 2021-05-20 08:55:19.814649 +0800 CST m=+3.000467753
Tick at 2021-05-20 08:55:20.81894 +0800 CST m=+4.004780216
ticker stopped
Tick at 2021-05-20 08:55:21.815348 +0800 CST m=+5.001210115
结果是每隔1秒将当前时间作为值push到通道,然后我们循环这个通道获取值。通过源码可以看到Ticker.C是一个time类型的channel。
源码:
type Ticker struct
C <-chan Time // The channel on which the ticks are delivered.
r runtimeTimer
工作池
func worker(id int, jobs <-chan int, results chan<- int)
for j := range jobs
fmt.Println("worker", id, "process job", j)
time.Sleep(time.Second * 2)
results <- j
func main()
jobs := make(chan int, 100)
results := make(chan int, 100)
// 开启5个进程
for w := 1; w <= 5; w++
go worker(w, jobs, results)
// 向通道push任务
for j := 1; j <= 9; j++
jobs <- j
close(jobs)
for r := 1; r <= 9; r++
<-results
result作用是告知主进程执行结束,当所有的执行结束后,主进程结束退出任务,如果没有result可能会导致子进程还没有结束,主进程就退出了。
结果
worker 3 process id 1
worker 1 process id 2
worker 2 process id 3
worker 1 process id 4
worker 2 process id 6
worker 3 process id 5
worker 2 process id 8
worker 1 process id 9
worker 3 process id 7
限速
func main()
// 限制每2秒执行一次请求
ticker := time.Tick(time.Second * 2)
for i := 1; i <= 5; i++
<-ticker
fmt.Println("request", i, time.Now())
// 先向burstylimiter push 3个值
limiter := make(chan time.Time, 3)
for i := 0; i < 3; i++
limiter <- time.Now()
// 然后开启另外一个线程,每2秒向burstylimiter push 一个值
go func()
for t := range time.Tick(time.Second * 2)
limiter <- t
()
// 最后实现效果,前三次没有限速,最后两次每2秒执行一次
for i := 1; i <= 5; i++
<-limiter
fmt.Println("request", i, time.Now())
结果:
request 1 2021-05-20 10:09:01.121992 +0800 CST m=+2.005258478
request 2 2021-05-20 10:09:03.117609 +0800 CST m=+4.000918022
request 3 2021-05-20 10:09:05.116884 +0800 CST m=+6.000235109
request 4 2021-05-20 10:09:07.11969 +0800 CST m=+8.003084206
request 5 2021-05-20 10:09:09.119841 +0800 CST m=+10.003278026
request 1 2021-05-20 10:09:09.119978 +0800 CST m=+10.003414895
request 2 2021-05-20 10:09:09.120101 +0800 CST m=+10.003538622
request 3 2021-05-20 10:09:09.12018 +0800 CST m=+10.003616297
request 4 2021-05-20 10:12:29.322124 +0800 CST m=+12.005434486
request 5 2021-05-20 10:12:31.322453 +0800 CST m=+14.005806367
效果:前5次,间隔2s,第6-8次,不间隔时间,9-10次再次间隔2s执行。
互斥锁
func main()
var state = make(map[int]int)
var mutex = &sync.Mutex
for w := 0; w < 10; w++
go func()
for
key := rand.Intn(5)
val := rand.Intn(100)
mutex.Lock() // 加锁
state[key] = val
mutex.Unlock() // 解锁
()
time.Sleep(time.Second)
fmt.Println("state:", state)
结果:
$ go run main.go
state: map[0:72 1:25 2:36 3:44 4:38]
当去掉互斥锁配置以后,代码报错,因为同时读写一块内存地址。
go状态协程
func main()
reads := make(chan *readOp)
writes := make(chan *writeOp)
// 通过select选择来保证同时只能读或写操作
go func()
var state = make(map[int]int)
for
select
case read := <-reads:
read.resp <- state[read.key]
case writes := <-writes:
state[writes.key] = writes.val
writes.resp <- true
()
for r := 0; r < 100; r++
go func()
for true
read := &readOp
key: rand.Intn(5),
resp: make(chan int),
reads <- read
()
for w := 0; w < 10; w++
go func()
for
write := &writeOp
key: rand.Intn(5),
val: rand.Intn(100),
resp: make(chan bool),
writes <- write
<-write.resp
()
time.Sleep(time.Second)
这里通过select选择来保证同时只有一个读或写操作,这样比通过互斥锁复杂。
排序
func main()
strs := []string"c", "a", "b"
sort.Strings(strs)
fmt.Println("Strings:", strs)
ints := [以上是关于Go by Example 中文练习的主要内容,如果未能解决你的问题,请参考以下文章