2017-04-05 10 views
3

私はゴリラ/ websocketパッケージのGodocを研究しました。 GolangゴリラWebSocketパッケージの同時実行性を保証する方法

はGodocでは、明らかに

同時実行 接続は1つの同時リーダーと1人の同時ライターをサポートすることが述べられています。

アプリケーションは1つ以下のゴルーチンが同時にかつ1個以下ゴルーチンがreadメソッド(NextReader、SetReadDeadline、ReadMessageを呼び出すこと(NextWriter、SetWriteDeadline、WriteMessage、WriteJSON、EnableWriteCompression、SetCompressionLevel)writeメソッドを呼び出すことを保証する責任があります、ReadJSON、SetPongHandler、SetPingHandler)を同時に実行します。

CloseメソッドとWriteControlメソッドは、他のすべての メソッドと並行して呼び出すことができます。

しかし、パッケージによって提供された例の一つで

func (c *Conn) readPump() { 
    defer func() { 
     hub.unregister <- c 
     c.ws.Close() 
    }() 
    c.ws.SetReadLimit(maxMessageSize) 
    c.ws.SetReadDeadline(time.Now().Add(pongWait)) 
    c.ws.SetPongHandler(func(string) error { 
     c.ws.SetReadDeadline(time.Now().Add(pongWait)); return nil 
    }) 
    for { 
     _, message, err := c.ws.ReadMessage() 
     if err != nil { 
      if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) { 
       log.Printf("error: %v", err) 
      } 
      break 
     } 
     message = bytes.TrimSpace(bytes.Replace(message, newline, space, -1)) 
     hub.broadcast <- message 
    } 
} 

出典:https://github.com/gorilla/websocket/blob/a68708917c6a4f06314ab4e52493cc61359c9d42/examples/chat/conn.go#L50

このライン

c.ws.SetPongHandler(func(string) error { 
    c.ws.SetReadDeadline(time.Now().Add(pongWait)); return nil 
}) 

このライン

_, message, err := c.ws.ReadMessage() 

はどのようにすべき、最初の行は、それがパッケージ内に作成し、2行目は、さらに重要な

serveWsを呼び出すゴルーチンで実行されているゴルーチンに呼び出される必要がありますので、コールバック関数があるので、同期していないことのようですI 1つ以上のゴルーチンがSetReadDeadline,ReadMessageSetPongHandlerSetPingHandlerと同時に呼び出さないようにしてください。

私は上記の関数を呼び出すたびにMutexロックをロックしてロックしようとしますが、その後ロックを解除しますが、すぐに問題が発生します。 forループでReadMessageが呼び出されるのは普通です(この例でも)。しかしMutextがReadMessage前にロックされている場合、その後、他の読み取り機能がロックを取得することはできませんし、次のメッセージが

この同時実行の問題を扱う上で任意のより良い方法はあり

を受信するまで実行しますか?前もって感謝します。

+0

私が誤読しなかった場合、pingとpongのコールバック関数は実際にReadMessage()が呼び出されるのと同じGoRoutineで実行されます。したがって、この例では並行性が保証されています。また、SetPingHandler()とSetPongHandler()も同期させる必要がありますが、この例ではReadMessage()が呼び出される前に呼び出されるため、問題ありません。 – user7509214

答えて

1

読み取りメソッドへの同時呼び出しがないようにするには、単一のゴルーチンからすべての読み取りメソッドを実行することをお勧めします。

ゴリラウェブソケットのすべての例では、質問に貼り付けた例を含めて、このアプローチを使用しています。この例では、readメソッドへのすべての呼び出しはreadPumpメソッドからのものです。 readPumpメソッドは、1つのゴルーチン上の接続に対して1回呼び出されます。したがって、接続読み取りメソッドは同時に呼び出されません。

section of the documentation on control messagesは、アプリケーションがプロセス制御メッセージへの接続を読み取る必要があることを示しています。これとゴリラ独自の例に基づいて、現在の実装のように、アプリケーションの読書のゴルーチンからping、pong、およびcloseハンドラが呼び出されると仮定することは安全だと思います。ドキュメンテーションがこれについてより明示的であればいいでしょう。たぶん問題を提出しますか?

関連する問題