2

数か月前、私はRPC ライブラリのために、Go でクローズ可能なイベント ループを実装する方法を考えていました。次のようにサーバーを簡単に閉じることができました。

type Server struct {
    listener net.Listener
    closeChan chan bool
    routines sync.WaitGroup
}

func (s *Server) Serve() {
    s.routines.Add(1)
    defer s.routines.Done()
    defer s.listener.Close()

    for {
        select {
            case <-s.closeChan:
                // close server etc.
            default:
                s.listener.SetDeadline(time.Now().Add(2 * time.Second))
                conn, _ := s.listener.Accept()
                // handle conn routine
        }
    }
}

func (s *Server) Close() {
    s.closeChan <- true // signal to close serve routine
    s.routines.Wait()
}

この実装で私が見つけた問題は、タイムアウトが含まれていることです。つまり、最小クローズ時間が実際よりも 2 秒長くなります。イベントループを作成するより慣用的な方法はありますか?

4

1 に答える 1

3

Goのイベントループはループである必要はないと思います。

別々のゴルーチンでクロージングと接続を処理する方が簡単に思えます。

go func() {
    <-s.closeChan
    // close server, release resources, etc.
    s.listener.Close()
}()
for {
    conn, err := s.listener.Accept()
    if err != nil {
         // log, return
    }
    // handle conn routine
}

チャネルを使用せずに、Close関数でリスナーを直接閉じることもできることに注意してください。ここで行ったことは、Listener.Acceptのエラー戻り値を使用して、ルーチン間の通信を容易にすることです。

クローズおよび接続処理の実装のある時点で、応答中にクローズしているリソースを保護する必要がある場合は、Mutexを使用できます。しかし、一般的にそれを回避することは可能です。

于 2012-11-22T07:34:50.517 に答える