Go - goroutines 之间的高性能通信?
Go - high performance communication between goroutines?
我正在尝试用 Go 编写一个小型游戏服务器。我基本上从 WebSocket 库 (https://github.com/gorilla/websocket).
复制了示例
服务器每秒执行函数s.tick()
,将当前时间发送给用户。这在用户不执行任何操作时工作正常。
当用户加入、离开或发送消息时,信息将通过三个通道之一发送(每个通道一个)并执行相应的操作,但是 s.tick()
要么跳过要么延迟。我注意到,如果用户一直执行操作,则永远不会调用 s.tick()
。
这是输出:
Mon, 05 Dec 2016 20:19:11 CET
Mon, 05 Dec 2016 20:19:12 CET
Mon, 05 Dec 2016 20:19:13 CET
Mon, 05 Dec 2016 20:19:15 CET
Mon, 05 Dec 2016 20:19:16 CET
Mon, 05 Dec 2016 20:19:17 CET
-- users joining and leaving
Mon, 05 Dec 2016 20:19:25 CET
Mon, 05 Dec 2016 20:19:26 CET
Mon, 05 Dec 2016 20:19:27 CET
Mon, 05 Dec 2016 20:19:28 CET
Mon, 05 Dec 2016 20:19:29 CET
我试图检查是什么导致了这些操作之间如此多的延迟(none 这些操作花费了很长时间),我唯一的想法是:
- 我的代码很糟糕(很有可能)
- Go 的频道很慢
我检查了循环开始时和 case 子句开始时的时间,通常需要超过 200 毫秒才能从通道接收数据。话虽如此,我怎样才能提高这个解决方案的性能?我似乎无法让服务器以每秒一次滴答的速度正常运行,更不用说 60 次了。
下面是我的代码片段:
type GameServer struct {
players map[*Player]bool
register chan *Player
unregister chan *Player
broadcast chan []byte
}
func (s *GameServer) broadcastMessage(msg []byte) {
for player := range s.players {
player.messages <- msg
}
}
func (s *GameServer) tick() {
s.broadcastMessage([]byte(time.Now().Format(time.RFC1123)))
}
// question is mostly related to this function
func (s *GameServer) run() {
for {
select {
case _ = <-time.NewTicker(time.Second).C:
s.tick()
case client := <-s.register:
s.players[client] = true
case client := <-s.unregister:
delete(s.players, client)
case msg := <-s.broadcast:
s.broadcastMessage(msg)
}
}
}
试试这个:
type GameServer struct {
players map[*Player]bool
register chan *Player
unregister chan *Player
broadcast chan []byte
ticker *time.Ticker //use a single "global" *time.Ticker
}
func (s *GameServer) broadcastMessage(msg []byte) {
for player := range s.players {
player.messages <- msg
}
}
func (s *GameServer) tick() {
s.broadcastMessage([]byte(time.Now().Format(time.RFC1123)))
}
// question is mostly related to this function
func (s *GameServer) run() {
for {
select {
case _ = <- s.Ticker.C: //use the "global" *time.Ticker instead of creating a new one every time
s.tick()
case client := <-s.register:
s.players[client] = true
case client := <-s.unregister:
delete(s.players, client)
case msg := <-s.broadcast:
s.broadcastMessage(msg)
}
}
}
我认为您不想在每次调用 run
时都创建一个新的 time.Ticker。以上应该可以解决您的问题。
我正在尝试用 Go 编写一个小型游戏服务器。我基本上从 WebSocket 库 (https://github.com/gorilla/websocket).
复制了示例服务器每秒执行函数s.tick()
,将当前时间发送给用户。这在用户不执行任何操作时工作正常。
当用户加入、离开或发送消息时,信息将通过三个通道之一发送(每个通道一个)并执行相应的操作,但是 s.tick()
要么跳过要么延迟。我注意到,如果用户一直执行操作,则永远不会调用 s.tick()
。
这是输出:
Mon, 05 Dec 2016 20:19:11 CET
Mon, 05 Dec 2016 20:19:12 CET
Mon, 05 Dec 2016 20:19:13 CET
Mon, 05 Dec 2016 20:19:15 CET
Mon, 05 Dec 2016 20:19:16 CET
Mon, 05 Dec 2016 20:19:17 CET
-- users joining and leaving
Mon, 05 Dec 2016 20:19:25 CET
Mon, 05 Dec 2016 20:19:26 CET
Mon, 05 Dec 2016 20:19:27 CET
Mon, 05 Dec 2016 20:19:28 CET
Mon, 05 Dec 2016 20:19:29 CET
我试图检查是什么导致了这些操作之间如此多的延迟(none 这些操作花费了很长时间),我唯一的想法是:
- 我的代码很糟糕(很有可能)
- Go 的频道很慢
我检查了循环开始时和 case 子句开始时的时间,通常需要超过 200 毫秒才能从通道接收数据。话虽如此,我怎样才能提高这个解决方案的性能?我似乎无法让服务器以每秒一次滴答的速度正常运行,更不用说 60 次了。
下面是我的代码片段:
type GameServer struct {
players map[*Player]bool
register chan *Player
unregister chan *Player
broadcast chan []byte
}
func (s *GameServer) broadcastMessage(msg []byte) {
for player := range s.players {
player.messages <- msg
}
}
func (s *GameServer) tick() {
s.broadcastMessage([]byte(time.Now().Format(time.RFC1123)))
}
// question is mostly related to this function
func (s *GameServer) run() {
for {
select {
case _ = <-time.NewTicker(time.Second).C:
s.tick()
case client := <-s.register:
s.players[client] = true
case client := <-s.unregister:
delete(s.players, client)
case msg := <-s.broadcast:
s.broadcastMessage(msg)
}
}
}
试试这个:
type GameServer struct {
players map[*Player]bool
register chan *Player
unregister chan *Player
broadcast chan []byte
ticker *time.Ticker //use a single "global" *time.Ticker
}
func (s *GameServer) broadcastMessage(msg []byte) {
for player := range s.players {
player.messages <- msg
}
}
func (s *GameServer) tick() {
s.broadcastMessage([]byte(time.Now().Format(time.RFC1123)))
}
// question is mostly related to this function
func (s *GameServer) run() {
for {
select {
case _ = <- s.Ticker.C: //use the "global" *time.Ticker instead of creating a new one every time
s.tick()
case client := <-s.register:
s.players[client] = true
case client := <-s.unregister:
delete(s.players, client)
case msg := <-s.broadcast:
s.broadcastMessage(msg)
}
}
}
我认为您不想在每次调用 run
时都创建一个新的 time.Ticker。以上应该可以解决您的问题。