Article directory
Goroutine pool
worker pool(goroutine池)
- Essentially a producer consumer model
- Can effectively control the number of goroutines to prevent skyrocketing
- need:
- Calculate the sum of the digits of a number, such as the number 123, the result is 1+2+3=6
- Generate random numbers for calculations
- The console output is as follows:
package main
import (
"fmt"
"math/rand"
)
type Job struct {
// id
Id int
// 需要计算的随机数
RandNum int
}
type Result struct {
// 这里必须传对象实例
job *Job
// 求和
sum int
}
func main() {
// 需要2个管道
// 1.job管道
jobChan := make(chan *Job, 128)
// 2.结果管道
resultChan := make(chan *Result, 128)
// 3.创建工作池
createPool(64, jobChan, resultChan)
// 4.开个打印的协程
go func(resultChan chan *Result) {
// 遍历结果管道打印
for result := range resultChan {
fmt.Printf("job id:%v randnum:%v result:%d\n", result.job.Id,
result.job.RandNum, result.sum)
}
}(resultChan)
var id int
// 循环创建job,输入到管道
for {
id++
// 生成随机数
r_num := rand.Int()
job := &Job{
Id: id,
RandNum: r_num,
}
jobChan <- job
}
}
// 创建工作池
// 参数1:开几个协程
func createPool(num int, jobChan chan *Job, resultChan chan *Result) {
// 根据开协程个数,去跑运行
for i := 0; i < num; i++ {
go func(jobChan chan *Job, resultChan chan *Result) {
// 执行运算
// 遍历job管道所有数据,进行相加
for job := range jobChan {
// 随机数接过来
r_num := job.RandNum
// 随机数每一位相加
// 定义返回值
var sum int
for r_num != 0 {
tmp := r_num % 10
sum += tmp
r_num /= 10
}
// 想要的结果是Result
r := &Result{
job: job,
sum: sum,
}
//运算结果扔到管道
resultChan <- r
}
}(jobChan, resultChan)
}
}
timer
timer
-
Timer: When the time is up, the execution is only executed once
-
type Timer
type Timer struct { C <-chan Time // 内含隐藏或非导出字段 }
The Timer type represents a single time event. When the Timer expires, the current time will be sent to C, unless the Timer was created by the AfterFunc function.
func NewTimer
func NewTimer(d Duration) *Timer
NewTimer creates a Timer that expires after at least d elapsed period of time, sending the current time to its own C field.
func AfterFunc
func AfterFunc(d Duration, f func()) *Timer
AfterFunc starts another goroutine to wait for the time period d to pass, and then calls f. It returns a Timer, and the wait and call to f can be canceled by calling its Stop method.
func (*Timer) Reset
func (t *Timer) Reset(d Duration) bool
Reset causes t to restart timing, and (after this method returns) waits for the time period d to elapse before it expires. Returns true if t is pending when called; returns false if t has expired or is stopped.
func (*Timer) Stop
func (t *Timer) Stop() bool
Stop stops the execution of Timer. Returns true if t is stopped; returns false if t has been stopped or expired. Stop does not close channel tC to avoid incorrect success of reads from this channel.
package main
import (
"fmt"
"time"
)
func main() {
// 1.timer基本使用
//timer1 := time.NewTimer(2 * time.Second)
//t1 := time.Now()
//fmt.Printf("t1:%v\n", t1)
//t2 := <-timer1.C
//fmt.Printf("t2:%v\n", t2)
// 2.验证timer只能响应1次
//timer2 := time.NewTimer(time.Second)
//for {
// <-timer2.C
// fmt.Println("时间到")
//}
// 3.timer实现延时的功能
//(1)
//time.Sleep(time.Second)
//(2)
//timer3 := time.NewTimer(2 * time.Second)
//<-timer3.C
//fmt.Println("2秒到")
//(3)
//<-time.After(2*time.Second)
//fmt.Println("2秒到")
// 4.停止定时器
//timer4 := time.NewTimer(2 * time.Second)
//go func() {
// <-timer4.C
// fmt.Println("定时器执行了")
//}()
//b := timer4.Stop()
//if b {
// fmt.Println("timer4已经关闭")
//}
// 5.重置定时器
timer5 := time.NewTimer(3 * time.Second)
timer5.Reset(1 * time.Second)
fmt.Println(time.Now())
fmt.Println(<-timer5.C)
for {
}
}
-
Ticker: Time is up, execute multiple times
-
type Ticker
type Ticker struct { C <-chan Time // 周期性传递时间信息的通道 // 内含隐藏或非导出字段 }
Ticker holds a channel and passes "ticks" to it at regular intervals.
func NewTicker
func NewTicker(d Duration) *Ticker
NewTicker returns a new Ticker, the Ticker contains a channel field, and will send the current time to the channel every time period d. It adjusts the time interval or discards tick messages to accommodate slow receivers. If d<=0 will panic. Closing the Ticker can release related resources.
func (*Ticker) Stop
func (t *Ticker) Stop()
Stop closes a Ticker. After closing, no more tick messages will be sent. Stop does not close the channel tC to avoid incorrect success of reads from this channel.
func Sleep
func Sleep(d Duration)
Sleep blocks the current goroutine for a period of at least d. When d<=0, Sleep will return immediately.
Example
func After
func After(d Duration) <-chan Time
After will send the current time to the return value after another thread has passed the time period d. Equivalent to NewTimer(d).C.
Example
func Tick
func Tick(d Duration) <-chan Time
Tick is a package of NewTicker, which only provides access to Ticker's channel. This function is convenient if you don't need to close the Ticker.
Example
package main
import (
"fmt"
"time"
)
func main() {
// 1.获取ticker对象
ticker := time.NewTicker(1 * time.Second)
i := 0
// 子协程
go func() {
for {
//<-ticker.C
i++
fmt.Println(<-ticker.C)
if i == 5 {
//停止
ticker.Stop()
}
}
}()
for {
}
}
select
select multiplexing
In some scenarios we need to receive data from multiple channels at the same time. When the channel is receiving data, if there is no data to receive, it will be blocked. You may write the following code to use traversal to achieve:
for{
// 尝试从ch1接收值
data, ok := <-ch1
// 尝试从ch2接收值
data, ok := <-ch2
…
}
Although this method can meet the requirement of receiving values from multiple channels, the operating performance will be much worse. To cope with this scenario, Go has a built-in select keyword, which can respond to operations of multiple channels at the same time.
The use of select is similar to the switch statement, it has a series of case branches and a default branch. Each case corresponds to the communication (receiving or sending) process of a channel. select will wait until the communication operation of a case is completed, and then execute the statement corresponding to the case branch. The specific format is as follows:
select {
case <-chan1:
// 如果chan1成功读到数据,则进行该case处理语句
case chan2 <- 1:
// 如果成功向chan2写入数据,则进行该case处理语句
default:
// 如果上面都没有成功,则进入default处理流程
}
- select can monitor one or more channels at the same time until one of the channels is ready
package main
import (
"fmt"
"time"
)
func test1(ch chan string) {
time.Sleep(time.Second * 5)
ch <- "test1"
}
func test2(ch chan string) {
time.Sleep(time.Second * 2)
ch <- "test2"
}
func main() {
// 2个管道
output1 := make(chan string)
output2 := make(chan string)
// 跑2个子协程,写数据
go test1(output1)
go test2(output2)
// 用select监控
select {
case s1 := <-output1:
fmt.Println("s1=", s1)
case s2 := <-output2:
fmt.Println("s2=", s2)
}
}
- If multiple channels are ready at the same time, randomly select one to execute
package main
import (
"fmt"
)
func main() {
// 创建2个管道
int_chan := make(chan int, 1)
string_chan := make(chan string, 1)
go func() {
//time.Sleep(2 * time.Second)
int_chan <- 1
}()
go func() {
string_chan <- "hello"
}()
select {
case value := <-int_chan:
fmt.Println("int:", value)
case value := <-string_chan:
fmt.Println("string:", value)
}
fmt.Println("main结束")
}
- Can be used to determine whether the pipeline is full
package main
import (
"fmt"
"time"
)
// 判断管道有没有存满
func main() {
// 创建管道
output1 := make(chan string, 10)
// 子协程写数据
go write(output1)
// 取数据
for s := range output1 {
fmt.Println("res:", s)
time.Sleep(time.Second)
}
}
func write(ch chan string) {
for {
select {
// 写数据
case ch <- "hello":
fmt.Println("write hello")
default:
fmt.Println("channel full")
}
time.Sleep(time.Millisecond * 500)
}
}