版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010986776/article/details/86308874
案例1:服务器负载控制
- 监听最大客户端连接数
- 服务端协程:只要服务器过载,就通知控制协程,并进入阻塞等待
- 控制协程:受到服务端预警,削减客户端数量,并通知服务端(预警已解除)
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
/*
服务器负载控制
·监听最大客户端连接数
·服务端协程:只要服务器过载,就通知控制协程,并进入阻塞等待
·控制协程:受到服务端预警,削减客户端数量,并通知服务端(预警已解除)
*/
type Server struct {
maxConnections int
connections int
chAlarm chan bool
cond *sync.Cond
}
/*服务端工厂方法*/
func NewServer(maxConnections int) *Server {
server := new(Server)
//初始化最大连接数
server.maxConnections = maxConnections
//初始化条件变量
server.cond = sync.NewCond(&sync.Mutex{})
//初始化预警管道
server.chAlarm = make(chan bool,0)
return server
}
/*启动过载处理器*/
func (s *Server) StartOverloadHandler() {
fmt.Println("StartOverloadHandler...")
go func() {
for {
//阻塞接收预警消息
<-s.chAlarm
fmt.Println("已收到负载预警")
//加锁削减客户端数量,并发送预警解除广播
s.cond.L.Lock()
<-time.After(3 * time.Second)
s.connections -= rand.Intn(s.maxConnections)
fmt.Println("s.connections=", s.connections)
//发送预警解除通知(会通知到Wait中的服务端主程序)
s.cond.Signal()
fmt.Println("过载预警已解除")
s.cond.L.Unlock()
}
}()
}
func (s *Server) Run() {
for {
//加锁检测是否过载
s.cond.L.Lock()
/*只要过载,就发送预警,并释放资源锁并阻塞等待*/
for s.connections >= s.maxConnections {
//发送预警
s.chAlarm <- true
fmt.Println("过载预警已发送")
//阻塞等待预警解除
s.cond.Wait()
}
//接入客户端
time.Sleep(1 * time.Second)
s.connections ++
fmt.Println("已接入客户端:s.connections=", s.connections)
s.cond.L.Unlock()
}
}
func main() {
server := NewServer(5)
//服务端跑起负载处理器
server.StartOverloadHandler()
//运行服务器主程序
server.Run()
}
案例2:城管来了
- 多个烧烤摊主协程监听城管大队的动向
- 只要出动就发消息通知工会主席,并进入阻塞等待至被唤醒,否则就提供露天烧烤
- 工会主席协程:收到烧烤摊主们的消息后,出面摆平城管大队,并广播通知所有烧烤摊主恢复营业
- 这里的广播我们使用了一对多的广播:cond.Broadcast()
代码实现
package main
import (
"fmt"
"sync"
"time"
)
/*
城管预警
·监听城管大队
·烧烤摊集群:
监听城管大队,
只要出动就发消息通知工会主席并进入阻塞等待至被唤醒
否则就提供露天烧烤
·工会主席:摆平城管大队,并广播通所有烧烤摊主
*/
func main() {
var dangerous = false
cond := sync.NewCond(&sync.Mutex{})
chDanger := make(chan string, 1)
for i := 1; i <= 3; i++ {
go func(index int) {
for {
//只要城管出来,就等待起来
cond.L.Lock()
for dangerous == true {
//发送预警()
select {
case chDanger <- "城管来了!!!":
fmt.Println(index,"城管来了!!!")
fmt.Println(index, ":进入蛰伏状态")
default: //已经有人发过了
}
fmt.Println(index, ":进入蛰伏状态")
cond.Wait()
}
cond.L.Unlock()
//城管没有出来
fmt.Println(index, ":提供露天烧烤...")
time.Sleep(3 * time.Second)
}
}(i)
}
go func() {
for {
select {
case <-chDanger:
//帮大家平事
cond.L.Lock()
time.Sleep(3 * time.Second)
dangerous = false
cond.Broadcast()//唤醒所有人
fmt.Println("事情已经摆平")
cond.L.Unlock()
default:
//日常生活
fmt.Println("工会主席的日常幸福生活...")
dangerous = true
time.Sleep(7 * time.Second)
}
}
}()
time.Sleep(365 * time.Second)
}