2016-12-05 2 views
2

Я пытаюсь написать небольшой игровой сервер в 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) 
     } 
    } 
} 
+4

Я бы предложил вам добавить глобальный тикер времени к вашей структуре GameServer, которая инициализируется только один раз и сменит ваш первый случай выбора на 's.ticker.C'. В настоящий момент вы создаете новый тикер каждый раз, когда вызывается функция запуска, поэтому он будет выполнять только галочку в экземпляре, где никакие другие каналы не имеют в них каких-либо данных в течение как минимум секунды, когда вызывается вызов, что объясняет поведение вас смотри. – 0xor1

+2

Вы создаете новый Тикер на каждой итерации, поэтому ваши утечки ресурсов превышают нестабильный интервал тика. – JimB

ответ

3

попробовать это:

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. Вышеупомянутое должно исправить ваши проблемы.

+0

Но я вызываю «run» только один раз, а затем он зацикливается до тех пор, пока процесс не будет убит. –

+1

все еще каждый раз, когда цикл for продолжается, вы создаете новый тикер, вы можете просто перемещать создание тикера за цикл for, в любом случае, он создает тикер на каждой итерации, что является причиной вашей ошибки. – 0xor1

+0

Получил, это действительно работает. Я неправильно понял ваш комментарий. Спасибо :) –

Смежные вопросы