Go 不会立即响应 GET 请求,它会在 ticker 完成后响应
Go not responding to GET request instantly, it response when ticker is done
我是围棋编程的新手,我尝试为多人游戏构建 API。如果我对 http://localhost:8080/create_game/gameName 进行 GET 请求。自动收报机完成后服务器对请求的响应。我需要立即从服务器获得响应,但是当自动收报机结束并且游戏超时并被删除时我得到了它。
这是我的代码:
var clients = make(map[*websocket.Conn]bool)
var broadcast = make(chan Game)
//GAME_TIMEOUT in seconds
const GAME_TIMEOUT = 20
//ID generating
var genID = 0
var games = []Game{}
var msg json.RawMessage
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
return true
},
}
type GameToSend struct {
Type string `json:"type"`
ID int `json:"id"`
Name string `json:"name"`
}
type Game struct {
ID int `json:"id"`
Name string `json:"name"`
Timer <-chan time.Time `json:"timestamp"`
}
func main() {
router := mux.NewRouter()
router.HandleFunc("/create_game/{name}", createGame)
router.HandleFunc("/game_events", handleConnections)
http.ListenAndServe(":8080", router)
}
func handleConnections(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
clients[conn] = true
for _, game := range games {
conn.WriteJSON(GameToSend{"game.created", game.ID, game.Name})
}
for {
err := conn.ReadJSON(&msg)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(msg)
}
}
}
func broadcastGame(game GameToSend) {
for conn := range clients {
conn.WriteJSON(game)
}
}
func createGame(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
genID++
game := Game{genID, params["name"], time.NewTimer(GAME_TIMEOUT * time.Second).C}
games = append(games, game)
broadcastGame(GameToSend{"game.created", game.ID, game.Name})
w.Write([]byte("response"))
checkTimeout(genID)
}
func deleteGame(actionType string, i int) {
for index, game := range games {
if game.ID == i {
broadcastGame(GameToSend{actionType, games[index].ID, games[index].Name})
games = games[:index+copy(games[index:], games[index+1:])]
}
}
}
func checkTimeout(id int) {
for _, game := range games {
if game.ID == id {
<-game.Timer
deleteGame("game.timeout", id)
}
}
}
知道如何解决吗?
您可以更改许多内容,但其中之一是通常不要 运行 响应客户端的代码中可能较长的 运行ning 任务。假设您有数百万个游戏,数量如此之多以至于每次调用 checkTimeout
都需要一秒钟来遍历所有游戏。每个请求都会有一秒钟的延迟才能得到完整的响应,这不是很好。最好通知另一个 goroutine 应该遍历游戏并清理过期的游戏,这样你可以 return 立即向客户端发送消息,同时在后台进行清理。
原来我看错了你在做什么,但这个建议仍然有效。在这种情况下,尽管 "long running function" 实际上会等到计时器在 returning 之前到期。这可能比一秒长得多!您的意思是 运行 在 goroutine 中吗? go checkTimeout(genID)
我是围棋编程的新手,我尝试为多人游戏构建 API。如果我对 http://localhost:8080/create_game/gameName 进行 GET 请求。自动收报机完成后服务器对请求的响应。我需要立即从服务器获得响应,但是当自动收报机结束并且游戏超时并被删除时我得到了它。
这是我的代码:
var clients = make(map[*websocket.Conn]bool)
var broadcast = make(chan Game)
//GAME_TIMEOUT in seconds
const GAME_TIMEOUT = 20
//ID generating
var genID = 0
var games = []Game{}
var msg json.RawMessage
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
return true
},
}
type GameToSend struct {
Type string `json:"type"`
ID int `json:"id"`
Name string `json:"name"`
}
type Game struct {
ID int `json:"id"`
Name string `json:"name"`
Timer <-chan time.Time `json:"timestamp"`
}
func main() {
router := mux.NewRouter()
router.HandleFunc("/create_game/{name}", createGame)
router.HandleFunc("/game_events", handleConnections)
http.ListenAndServe(":8080", router)
}
func handleConnections(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
clients[conn] = true
for _, game := range games {
conn.WriteJSON(GameToSend{"game.created", game.ID, game.Name})
}
for {
err := conn.ReadJSON(&msg)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(msg)
}
}
}
func broadcastGame(game GameToSend) {
for conn := range clients {
conn.WriteJSON(game)
}
}
func createGame(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
genID++
game := Game{genID, params["name"], time.NewTimer(GAME_TIMEOUT * time.Second).C}
games = append(games, game)
broadcastGame(GameToSend{"game.created", game.ID, game.Name})
w.Write([]byte("response"))
checkTimeout(genID)
}
func deleteGame(actionType string, i int) {
for index, game := range games {
if game.ID == i {
broadcastGame(GameToSend{actionType, games[index].ID, games[index].Name})
games = games[:index+copy(games[index:], games[index+1:])]
}
}
}
func checkTimeout(id int) {
for _, game := range games {
if game.ID == id {
<-game.Timer
deleteGame("game.timeout", id)
}
}
}
知道如何解决吗?
您可以更改许多内容,但其中之一是通常不要 运行 响应客户端的代码中可能较长的 运行ning 任务。假设您有数百万个游戏,数量如此之多以至于每次调用 checkTimeout
都需要一秒钟来遍历所有游戏。每个请求都会有一秒钟的延迟才能得到完整的响应,这不是很好。最好通知另一个 goroutine 应该遍历游戏并清理过期的游戏,这样你可以 return 立即向客户端发送消息,同时在后台进行清理。
原来我看错了你在做什么,但这个建议仍然有效。在这种情况下,尽管 "long running function" 实际上会等到计时器在 returning 之前到期。这可能比一秒长得多!您的意思是 运行 在 goroutine 中吗? go checkTimeout(genID)