Я пытаюсь написать небольшой игровой сервер в Go. Я в основном копировал пример из библиотеки WebSocket (https://github.com/gorilla/websocket).Go - высокая производительность связи между goroutines?
С каждой секундой сервер выполняет функцию 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
Я попытался проверить, что вызывает столько задержки между действиями (ни одно из этих действий не предпринимает много времени), и моя единственная мысль в том, что:
- мой код просто плохо (очень вероятно)
- каналы Go являются медленными
I C hecked time в начале цикла и в начале предложения 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)
}
}
}
Я бы предложил вам добавить глобальный тикер времени к вашей структуре GameServer, которая инициализируется только один раз и сменит ваш первый случай выбора на 's.ticker.C'. В настоящий момент вы создаете новый тикер каждый раз, когда вызывается функция запуска, поэтому он будет выполнять только галочку в экземпляре, где никакие другие каналы не имеют в них каких-либо данных в течение как минимум секунды, когда вызывается вызов, что объясняет поведение вас смотри. – 0xor1
Вы создаете новый Тикер на каждой итерации, поэтому ваши утечки ресурсов превышают нестабильный интервал тика. – JimB