说明
最简单的goroutine
1 | //建立一个主goroutine(main)和一个副goroutine(spinner) |
并发时钟服务器
时钟服务器为每个连接提供一个goroutine
服务器
1 | func main(){ |
客户端
1 |
|
并发回声服务器
并发回声服务器中对每个连接都采用多个goroutine处理。服务器并发处理每个客户端的连接且对每个连接的处理本身也是并发的
服务器
1 | func main(){ |
客户端
1 | func main(){ |
无缓冲通道
对于上述并发回声服务器的客户端而言,若客户端接收到结束符(Ctrl+D)则mustCopy(conn,os.Stdin)运行结束,程序结束。不管后台goroutine是否还在运行。加入无缓冲通道进行同步。
客户端
初始版本
1 | func main(){ |
流程:若客户端输入(Ctrl+D):mustCopy(conn,os.Stdin)结束->服务端看到EOF,关闭连接—>io.Copy结束,输出“done”,结束运行
改进版本
读写分离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//输入内容写入到输出
func mustCopy(w io.Writer,r io.Reader){
_, err:= io.Copy(w,r)
if err!= nil {
log.Fatal(err)
}
}
func main(){
//解析tcp地址
tcpAddr, err := net.ResolveTCPAddr("","localhost:8008")
if err != nil{
log.Fatal(err)
}
conn , err := net.DialTCP("tcp",nil,tcpAddr)
if err != nil {
log.Fatal(err)
}
//写同步通道
writeDone := make(chan struct{})
//读同步通道
readDone := make(chan struct{})
go func(){
//从conn中读入内容到输出
io.Copy(os.Stdout,conn)
log.Println("readDone")
//已经读了
readDone <- struct{}{}
}()
//从输入写入到conn
mustCopy(conn,os.Stdin)
//已经写了
writeDone <- struct{}{}
//先关闭写通道,服务端不会再接收内容了
conn.CloseWrite()
<- writeDone
//再关闭读通道,已经读完服务端内容了
conn.CloseRead()
<- readDone
}
并发web爬虫
1 | func crawl(url string) []string { |
select 多路复用
select 类似switch,case语句指定一次通信,若此次通信发生则该情况下对应语句,其他通信将不会发生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
29func main() {
abort := make(chan struct{})
go func() {
//等待从输入读取一个字节
os.Stdin.Read(make([]byte, 1))
abort <- struct{}{}
}()
fmt.Println("Commencing countdown. Press return to abort.")
//tick 每过一秒,进行发送
tick := time.Tick(1 * time.Second)
for countdown := 10; countdown > 0; countdown-- {
fmt.Println(countdown)
select {
//若tick完成发送了,则接收,完成本次循环
case <-tick:
// Do nothing.
//若abort 可接收了,则接收,完成本次循环
case <-abort:
fmt.Println("Launch aborted!")
return
}
}
launch()
}
func launch() {
fmt.Println("Lift off!")
并发目录遍历
不限制并发数的目录遍历
1 | package main |
限制并发数的目录遍历
1 | package main |
增加取消功能的目录遍历
关于通过的关闭
关闭通道后,无法进行发送操作,但可以进行接收操作。若原通道为空,关闭后通道内将包含一个默认值。其值为通道类型的默认值(对int类型为0,对string类型为空字符)1
2
3
4
5
6
7func main(){
done := make(chan int )
//<-done //报错
close(done)
fmt.Println(<-done)//输出0
fmt.Println(<-done)//输出0
}
取消
1 | package main |
聊天服务器
服务端
1 | package main |
客户端
1 | package main |