并发
更新于 2023-12-06
关键字
Goroutine
goroutine是用户级别线程
main() 函数是第一个协程
函数之前使用go关键字即创建
| Go |
|---|
| func main(){
login()
go launch()
}
func main(){
login()
go func() { //匿名函数
launch()
}()
}
|
channel
协程之间通信的队列
声明
var chanName chan ElementType
| Go |
|---|
| ch := make(chan int) //创建非缓存channel
ch := make(chan int, 10) //创建有缓存的channel
|
收发数据
channel 之后使用 <-表示发送数据
channel 之前使用 <- 表示接收数据
非缓存channel的读写都是阻塞操作
| Go |
|---|
| ch <- x // sends (or write) x through channel ch
x = <-ch // x receives (or reads) data sent to the channel ch
<-ch // receives data, but the result is discarded
|
使用内置的 close() 函数关闭带有发送功能的channel
关闭channel后,不能再往channel发送消息,否则程序将发生严重错误
| Go |
|---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 | func checkAPI(api string, ch chan string) {
_, err := http.Get(api)
if err != nil {
ch <- fmt.Sprintf("ERROR: %s is down!\n", api)
return
}
ch <- fmt.Sprintf("SUCCESS: %s is up and running!\n", api)
}
ch := make(chan string)
for _, api := range apis {
go checkAPI(api, ch)
}
fmt.Print(<-ch)
|
无缓冲 channel
使用make()函数创建channel时,会默认创建一个无缓冲channel
无缓冲channel在同步发送和接收操作
| Go |
|---|
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
52 | package main
import (
"fmt"
"net/http"
"time"
)
func main() {
start := time.Now()
apis := []string{
"https://management.azure.com",
"https://dev.azure.com",
"https://api.github.com",
"https://outlook.office.com/",
"https://api.somewhereintheinternet.com/",
"https://graph.microsoft.com",
}
ch := make(chan string)
for _, api := range apis {
go checkAPI(api, ch)
}
for i := 0; i < len(apis); i++ {
fmt.Print(<-ch)
}
elapsed := time.Since(start)
fmt.Printf("Done! It took %v seconds!\n", elapsed.Seconds())
}
func checkAPI(api string, ch chan string) {
_, err := http.Get(api)
if err != nil {
ch <- fmt.Sprintf("ERROR: %s is down!\n", api)
return
}
ch <- fmt.Sprintf("SUCCESS: %s is up and running!\n", api)
}
输出
ERROR: https://api.somewhereintheinternet.com/ is down!
SUCCESS: https://api.github.com is up and running!
SUCCESS: https://management.azure.com is up and running!
SUCCESS: https://dev.azure.com is up and running!
SUCCESS: https://graph.microsoft.com is up and running!
SUCCESS: https://outlook.office.com/ is up and running!
Done! It took 0.602099714 seconds!
|
有缓冲 channel
当channel的的容量多余1时,channel就是有缓存的channel
| Go |
|---|
| ch := make(chan string, 10)
|
发送数据时数据将被存储到队列中
接收操作将从队列中删除
当channel满时,发送操作将阻塞
当channel空时,读取操作将阻塞
| Go |
|---|
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 | package main
import (
"fmt"
)
func send(ch chan string, message string) {
ch <- message
}
func main() {
size := 4
ch := make(chan string, size)
send(ch, "one")
send(ch, "two")
send(ch, "three")
send(ch, "four")
fmt.Println("All data sent to the channel ...")
for i := 0; i < size; i++ {
fmt.Println(<-ch)
}
fmt.Println("Done!")
}
|
| Go |
|---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | func main() {
size := 2
ch := make(chan string, size)
send(ch, "one")
send(ch, "two")
go send(ch, "three")
go send(ch, "four")
fmt.Println("All data sent to the channel ...")
for i := 0; i < 4; i++ {
fmt.Println(<-ch)
}
fmt.Println("Done!")
}
|
Channel 方向
当channel作为参数时,可指定收发方向
| Go |
|---|
| chan<- int // 只发送数据
<-chan int // 是接收数据
|
| Go |
|---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | package main
import "fmt"
func send(ch chan<- string, message string) {
fmt.Printf("Sending: %#v\n", message)
ch <- message
}
func read(ch <-chan string) {
fmt.Printf("Receiving: %#v\n", <-ch)
}
func main() {
ch := make(chan string, 1)
send(ch, "Hello World!")
read(ch)
}
|
多路复用
select可以同时监听多个channel
当收到多个事件,会随机选择一个处理
| Go |
|---|
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 | package main
import (
"fmt"
"time"
)
func process(ch chan string) {
time.Sleep(3 * time.Second)
ch <- "Done processing!"
}
func replicate(ch chan string) {
time.Sleep(1 * time.Second)
ch <- "Done replicating!"
}
func main() {
ch1 := make(chan string)
ch2 := make(chan string)
go process(ch1)
go replicate(ch2)
for i := 0; i < 2; i++ {
select {
case process := <-ch1:
fmt.Println(process)
case replicate := <-ch2:
fmt.Println(replicate)
}
}
}
|