如题,记录一些自认为有趣的特性

定时器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//定时器1执行完毕,协程定时器2终止

package main

import (
"fmt"
"time"
)

func main() {
timer1 := time.NewTimer(2 * time.Second)
<-timer1.C
fmt.Println("timer1 is done")

timer2 := time.NewTimer(2 * time.Second)

//开一个协程,此时程序一边运行协程func,一边跑下面的stop,因为timer2会立即stop,所以不会打印timer2 is done
go func() {
<-timer2.C
fmt.Println("timer2 is done")
}()
stop := timer2.Stop()
if stop {
fmt.Println("timer2 is stop")
}
}

打点器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//打点器700ms一次,程序等待3s,输出working
//有一个通道用来通知协程关闭

package main

import (
"fmt"
"time"
)

func main() {

//创建打点器实例,后面需要释放这个实例
ticker := time.NewTicker(700 * time.Millisecond)

ch := make(chan bool)

//协程开始,用for循环不断得到打点器的值,输出ticker now
go func() {
for {
select {
case t := <-ticker.C:
fmt.Println("Tick at", t)
case <-ch:
return
}
}
}()
time.Sleep(3 * time.Second)
ticker.Stop() //打点器停止
ch <- true //协程停止
fmt.Println("ticker stopped")

}

结果:

alt text

时间限制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
//速度限制

package main

import (
"fmt"
"time"
)

func main() {
////七个任务,300ms一个,无处理爆发任务能力
//tick := time.Tick(300 * time.Millisecond) //打点器,ticker需要先实例且课手动停止,tick直接运行到程序结束
//
//re := make(chan int, 7)
//for i := 1; i <= 7; i++ {
// re <- i
//}
//close(re)
//
//for r := range re {
// <-tick
// fmt.Println("time ", r, time.Now())
//}

//七个任务,300ms一个,可处理4个爆发任务(并发)
//能处理四个爆发任务,即存有四个时间令牌
conti := make(chan time.Time, 4)
for i := 0; i <= 3; i++ {
conti <- time.Now()
}

go func() {
//开一个协程,隔300ms发送一个时间令牌表示可以处理事件+1
//通道conti容量是4
for t := range time.Tick(300 * time.Millisecond) {
conti <- t
}
}()

//模拟任务
requt := make(chan int, 7)
for i := 0; i < 7; i++ {
requt <- i
}
close(requt)
//任务处理,前四个在通道里已经有时间令牌了,很迅速的完成,后面三个保持300ms左右完成一个
for r := range requt {
<-conti
fmt.Println(r, " is done", time.Now())
}
}

原子计数器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//原子计数器,20个协程,每个累加50次

package main

import (
"fmt"
"sync"
"sync/atomic"
)

func main() {
var ops uint64

var wg sync.WaitGroup

for i := 1; i <= 20; i++ {
wg.Add(1)
go func() {
for j := 0; j < 50; j++ {
atomic.AddUint64(&ops, 1)
//直接到地址处加1,所以多协程不会出错
}
wg.Done()
}()
}
wg.Wait()
fmt.Println(ops)
}

互斥锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//互斥锁
//aa叠加500+500次,bb叠加400次
//结构体里互斥锁,结构体方法:锁上,执行动作,解锁
//WaitGrounp保证协程
//单独函数执行累加
//使用WaitGrounp的时候,每个协程完毕后要运行wg.Done通知wg.WaitGroup任务结束,否则会一直被wg.Wait阻塞

package main

import (
"fmt"
"sync"
)

type Counti struct {
mu sync.Mutex
contner map[string]int
}

func (c *Counti) inc(name string) {
c.mu.Lock()
defer c.mu.Unlock()
c.contner[name] += 1
}

func main() {
c := Counti{
contner: map[string]int{"aa": 0, "bb": 0},
}

// wg := sync.WaitGroup{}
var wg sync.WaitGroup

prog := func(name string, n int) {
for i := 0; i < n; i++ {
c.inc(name)
}
wg.Done()
}

wg.Add(3)
go prog("aa", 500)
go prog("aa", 500)
go prog("bb", 400)
wg.Wait()
fmt.Println(c.contner)
}

panic&revocer&defer

程序执行过程中遇到显式的panic会立即开始回溯调用栈,只有 defer 语句能在这个回溯过程中被执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import "fmt"

func performTask() {
// 使用 defer 语句,在其中调用 recover 尝试捕获 panic
defer func() {
if r := recover(); r != nil {
// 若 recover 返回值不为 nil,说明成功捕获到 panic
fmt.Println("捕获到 panic:", r)
}
}()
fmt.Println("任务开始执行")
// 触发 panic
panic("执行任务时出现严重错误")
fmt.Println("这行代码不会被执行")
}

func main() {
fmt.Println("程序开始")
performTask()
fmt.Println("程序继续执行,未崩溃")
}

时间戳

时间戳是一个表示特定时间点的单一数值,通常是从某个固定的起始时间(纪元)开始计算,到指定时间点所经过的时间量。在 Unix 系统中,纪元是 1970 年 1 月 1 日 00:00:00 UTC,常见的时间戳单位有秒、毫秒、微秒、纳秒等。例如,1672531200 这个秒级时间戳代表的是从 1970 年 1 月 1 日 00:00:00 UTC 到 2023 年 1 月 1 日 00:00:00 UTC 所经过的秒数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package main

import (
"fmt"
"time"
)

func main() {

now := time.Now()//当下时间
secs := now.Unix()//从纪年(到当下时间所经历的秒数
nanos := now.UnixNano()//纳秒数量
fmt.Println(now)

millis := nanos / 1000000
fmt.Println(secs)
fmt.Println(millis)
fmt.Println(nanos)

fmt.Println(time.Unix(secs, 0))
fmt.Println(time.Unix(0, nanos))

// 创建一个指定的时间对象
specifiedTime, err := time.Parse("2006-01-02 15:04:05", "2024-10-01 12:00:00")
if err != nil {
fmt.Println("时间解析错误:", err)
return
}

// 获取指定时间的秒级时间戳
timestamp := specifiedTime.Unix()
fmt.Println("指定时间的秒级时间戳:", timestamp)
}