共计 10924 个字符,预计需要花费 28 分钟才能阅读完成。
通道同步
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 := []int{1, 6, 3, 5, 2}
sort.Ints(ints)
fmt.Println("Ints:", ints)
// 判断是否排序
s := sort.IntsAreSorted(ints)
fmt.Println("Sorted:", s)
}
自定义规定排序
以字符串长度排序
type ByLength []string
func (b ByLength) Len() int {return len(b)
}
func (b ByLength) Swap(i, j int) {b[i], b[j] = b[j], b[i]
}
func (b ByLength) Less(i, j int) bool {return len(b[i]) < len(b[j])
}
func main() {fruits := []string{"apple", "banana", "kiwi", "orage"}
sort.Sort(ByLength(fruits))
fmt.Println(fruits)
}
后果
$ go run main.go
[kiwi apple orage banana]
正则表达式
func main() {match, _ := regexp.MatchString("p([a-z]+)ch", "peach")
fmt.Println(match)
r, _ := regexp.Compile("p([a-z]+)ch")
fmt.Println(r.MatchString("peach"))
fmt.Println(r.Match([]byte("peach")))
fmt.Println(r.FindString("peach punch"))
fmt.Println(r.FindStringIndex("peach punch"))
fmt.Println(r.FindStringSubmatch("peach punch"))
fmt.Println(r.FindStringSubmatchIndex("peach punch"))
fmt.Println(r.FindAllString("peach punch pinch", -1))
fmt.Println(r.FindAllString("peach punch pinch", 2))
fmt.Println(r.FindAllString("peach punch pinch", 1))
fmt.Println(r.FindAllStringSubmatch("peach pinch punch", -1))
fmt.Println(r.FindAllStringSubmatchIndex("peach pinch punch", -1))
r = regexp.MustCompile("p([a-z]+)ch")
fmt.Println(r)
fmt.Println(r.ReplaceAllString("a peach", "<fruit>"))
in := []byte("a peach")
out := r.ReplaceAllFunc(in, bytes.ToUpper)
fmt.Println(string(out))
}
后果:
true
true
true
peach
[0 5]
[peach ea]
[0 5 1 3]
[peach punch pinch]
[peach punch]
[peach]
[[peach ea] [pinch in] [punch un]]
[[0 5 1 3] [6 11 7 9] [12 17 13 15]]
p([a-z]+)ch
a <fruit>
a PEACH
工夫戳
func main() {now := time.Now()
secs := now.Unix()
nanos := now.UnixNano()
fmt.Println(now)
fmt.Println(secs)
fmt.Println(nanos)
fmt.Println(time.Unix(secs, 0))
fmt.Println(time.Unix(0, nanos))
}
后果:
2021-05-21 09:19:47.347155 +0800 CST m=+0.000135175
1621559987
1621559987347155000
2021-05-21 09:19:47 +0800 CST
2021-05-21 09:19:47.347155 +0800 CST
数字解析
将字符串解析成对应的数字类型,当遇到无奈解析时,会报错。
func main() {f, _ := strconv.ParseFloat("1.234", 64)
fmt.Println(f)
i, _ := strconv.ParseInt("1234", 0, 64)
fmt.Println(i)
k, _ := strconv.Atoi("135")
fmt.Println(k)
_, e := strconv.Atoi("wat")
fmt.Println(e)
}
后果:
1.234
1234
135
strconv.Atoi: parsing "wat": invalid syntax
解析 URL 地址
func main() {
s := "postgres://user:pass@host.com:5432/path?k=v#f"
u, err := url.Parse(s)
if err != nil {panic(err)
}
fmt.Println(u.User.Username())
p, _ := u.User.Password()
fmt.Println(p)
fmt.Println(u.Host)
fmt.Println(strings.Split(u.Host, ":")[0])
fmt.Println(strings.Split(u.Host, ":")[1])
// 获取门路
fmt.Println(u.Path)
// 获取参数值
fmt.Println(u.Fragment)
fmt.Println(u.RawQuery)
}
后果:
$ go run main.go
user
pass
host.com:5432
host.com
5432
/path
f
k=v
SHA1 散列
func main() {
s := "sha1 shis string"
// 创立一个 sha1 对象
h := sha1.New()
// 对字符串解决
h.Write([]byte(s))
// sumk 能够用来对现有字符串切片追加额定字节,个别不须要
bs := h.Sum(nil)
fmt.Println(s)
fmt.Printf("%x\n", bs)
}
后果:
sha1 shis string
6bf8cad402882fb0fc2aed041dcc79b8e686cfc6
Scan 过滤
func main() {
// 从命令行获取数据
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {ucl := strings.ToUpper(scanner.Text())
fmt.Println(ucl)
}
if err := scanner.Err(); err != nil {fmt.Fprintln(os.Stderr, "error", err)
os.Exit(1)
}
}
后果:
$ echo "nihaoya" |go run main.go
NIHAOYA
命令行参数
func main() {
argsWithProg := os.Args
argsWithoutProg := os.Args[1:]
arg := os.Args[3]
fmt.Println(argsWithProg)
fmt.Println(argsWithoutProg)
fmt.Println(arg)
}
后果:
[/var/folders/p0/cv96ln_j6t7d6g_lwfwcqgqc0000gn/T/go-build765472776/b001/exe/main a b c d]
[a b c d]
c
环境变量
func main() {os.Setenv("FOO", "1")
fmt.Println("FOO:", os.Getenv("FOO"))
fmt.Println("BAR:", os.Getenv("BAR"))
for _, e := range os.Environ() {pair := strings.Split(e, "=")
fmt.Println(pair[0])
}
}
后果:
FOO: 1
BAR:
__INTELLIJ_COMMAND_HISTFILE__
HOME
__CF_USER_TEXT_ENCODING
LOGIN_SHELL
PATH
LC_CTYPE
USER
SSH_AUTH_SOCK
TMPDIR
SHELL
LOGNAME
XPC_SERVICE_NAME
GO111MODULE
GOPATH
XPC_FLAGS
GOROOT
执行系统命令
func main() {
// 执行工夫命令
dateCmd := exec.Command("date")
dateOut, err := dateCmd.Output()
if err != nil {panic(err)
}
fmt.Println(string(dateOut))
// 执行 ls 命令
lsCmd := exec.Command("bash", "-c", "ls -a -l -h")
lsOut, err := lsCmd.Output()
if err != nil {panic(err)
}
fmt.Println(string(lsOut))
// 执行 grep 命令
grepCmd := exec.Command("grep", "hello")
// 获取输出和输入对象
grepIn, _ := grepCmd.StdinPipe()
grepOut, _ := grepCmd.StdoutPipe()
// 开始执行
grepCmd.Start()
// 输出字符
grepIn.Write([]byte("hello grep\ngoodbye grep"))
grepIn.Close()
// 读取输入
grepBytes, _ := ioutil.ReadAll(grepOut)
grepCmd.Wait()
fmt.Println("> grep hello")
fmt.Println(string(grepBytes))
}
后果:
$ go run main.go
Fri May 21 11:33:32 CST 2021
total 160
drwxr-xr-x 17 liangkai admin 544B May 21 11:33 .
drwxr-xr-x@ 21 liangkai admin 672B May 17 17:40 ..
-rw-r--r--@ 1 liangkai admin 10K May 17 18:48 .DS_Store
-rw-r--r-- 1 liangkai admin 67B Dec 21 12:08 .env
drwxr-xr-x 8 liangkai admin 256B May 19 17:47 .idea
drwxr-xr-x 3 liangkai admin 96B Apr 30 08:13 .vscode
drwxr-xr-x 4 liangkai admin 128B Apr 30 15:37 Other
drwxr-xr-x 4 liangkai admin 128B Dec 21 09:13 PracChan
drwxr-xr-x 4 liangkai admin 128B Apr 12 16:54 PracCodeSvn
drwxr-xr-x 3 liangkai admin 96B Mar 3 10:59 PracExporter
drwxr-xr-x 7 liangkai admin 224B Apr 30 15:37 PracHttp
drwxr-xr-x 5 liangkai admin 160B Dec 21 09:10 PracInterface
drwxr-xr-x 6 liangkai admin 192B Apr 30 14:46 base
-rw-r--r-- 1 liangkai admin 147B Feb 20 18:44 config.ini
-rw-r--r-- 1 liangkai admin 798B Apr 30 15:41 go.mod
-rw-r--r-- 1 liangkai admin 52K Apr 30 15:41 go.sum
-rw-r--r--@ 1 liangkai admin 725B May 21 11:33 main.go
> grep hello
hello grep
零碎信号
func main() {sigs := make(chan os.Signal, 1)
done := make(chan bool, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
sig := <-sigs
fmt.Println()
fmt.Println(sig)
done <- true
}()
fmt.Println("waitting signal")
<-done
fmt.Println("exiting")
}
后果:
$ go run main.go
waitting signal
^C
interrupt
exiting
正文完