dongwen9051 2018-05-11 10:40
浏览 101
已采纳

去不立即响应GET请求,完成报价后立即响应

I'm new to Go programming and I try to build API for a multiplayer game. If I make GET req to the http://localhost:8080/create_game/gameName . Server response to the request when ticker is done. I need to get response from a server instantly but I got it when ticker is over and game is timeouted and deleted.

Here is my code:

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)
        }
    }
}

any idea how to fix it?

  • 写回答

1条回答 默认 最新

  • dtkl55257 2018-05-11 11:22
    关注

    There are a number of things you could change, but one of them is in general don't run potentially long running tasks in the code that is responding to clients. Imagine you have millions of games, so many that each call to checkTimeout takes a second to iterate over all the games. Every request would have a one second delay to get a complete response, not great. It would be better to signal another goroutine should iterate over the games and clean up expired ones, that way you can return immediately to the client while the clean up happens in the background.

    Turns out I misread what you are doing, but the advice is still valid. In this case though the "long running function" actually waits until the timer expires before returning. That could be significantly longer than one second! Were you meaning to run that in a goroutine? go checkTimeout(genID)

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 在若依框架下实现人脸识别
  • ¥15 网络科学导论,网络控制
  • ¥100 安卓tv程序连接SQLSERVER2008问题
  • ¥15 利用Sentinel-2和Landsat8做一个水库的长时序NDVI的对比,为什么Snetinel-2计算的结果最小值特别小,而Lansat8就很平均
  • ¥15 metadata提取的PDF元数据,如何转换为一个Excel
  • ¥15 关于arduino编程toCharArray()函数的使用
  • ¥100 vc++混合CEF采用CLR方式编译报错
  • ¥15 coze 的插件输入飞书多维表格 app_token 后一直显示错误,如何解决?
  • ¥15 vite+vue3+plyr播放本地public文件夹下视频无法加载
  • ¥15 c#逐行读取txt文本,但是每一行里面数据之间空格数量不同