go关键字基本上就是新开一个goroutine(差不多就是线程),然后执行对应的方法。
当一个程序启动时,其主函数即在一个单独的goroutine中运行,我们叫它main goroutine。在语法上,go语句是一个普通的函数或方法调用前加上关键字go。
f() // 普通阻塞方法
go f() // 创建一个新的goroutine然后执行该方法
Channels就是一个读取写入阻塞的队列。两个或多个goroutine通过Channels来完成协作,一般是一个goroutine读,多个goroutine写。
使用内置的make函数,我们可以创建一个channel:
ch := make(chan int) // 可以写入读写int类型的channel
一个channel有发送和接受两个主要操作,都是通信行为。一个发送语句将一个值从一个goroutine通过channel发送到另一个执行接收操作的goroutine。
ch <‐ x //写入
x = <‐ch // 读取
<‐ch // 读取并直接舍弃
一个基于无缓存Channels的发送操作将导致发送者goroutine阻塞,直到另一个goroutine在相同的Channels上执行接收操作(就是和阻塞队列一样的同步机制)
select语句意思也非常简单,就是从多个阻塞队列中只要有任意一个不再阻塞,select就会被执行,可以看成是switch的同步版
select {
case <‐ch1:
// ...
case x := <‐ch2:
// ...use x...
case ch3 <‐ y:
// ...
default:
// ...
}
交替打印
ch := make(chan int, 1)
for i := 0; i < 10; i++ {
select {
case x := <‐ch:
fmt.Println(x) // "0" "2" "4" "6" "8"
case ch <‐ i:
}
}
一个简易的聊天服务器程序
package main
import (
"net"
"log"
"bufio"
"fmt"
)
//该程序一共有2n+2个线程(n为客户端数量)
//其中一个线程监听客户端连接,一个线程负责广播消息,然后每个客户端有两个线程,一个负责读取消息,一个负责写消息
func main(){
//设置网卡为监听模式
listener,err:=net.Listen("tcp","localhost:8000")
//创建失败 打印错误日志
if err!=nil {
log.Fatal(err)
}
//广播消息线程
go broadcaster()
//死循环监听客户端连接
for{
conn,err:=listener.Accept()
if err!=nil{
log.Fatal(err)
continue
}
go handleConn(conn)
}
}
//每个客户端开启一个单独的线程进行服务
func handleConn(conn net.Conn) {
ch:=make(chan string)
go clientWriter(conn,ch)
//初始信息
who:=conn.RemoteAddr().String()
ch<-"You are "+who
messages<-who+" has arrived"
entering<-ch
//循环读取客户端的输入,然后群发
input:=bufio.NewScanner(conn)
for input.Scan(){
messages<-who+":"+input.Text()
}
//客户端退出
leaving<-ch
messages<-who+" has left"
//关闭连接
conn.Close()
}
func clientWriter(conn net.Conn, ch<- chan string) {
for msg:=range ch{
fmt.Fprintln(conn,msg)
}
}
type client chan<- string
//三个channel用来同步消息
var (
entering=make(chan client)
leaving=make(chan client)
messages=make(chan string)
)
func broadcaster() {
clients:=make(map[client]bool)
for{
select {
case msg:=<-messages:
for cli:=range clients {
cli<-msg
}
case cli:=<-entering:
clients[cli]=true
case cli:=<-leaving:
delete(clients,cli)
close(cli)
}
}
}
欢迎关注我的github https://github.com/luckyCatMiao