Commit 2bf2f0cb authored by David Fifield's avatar David Fifield
Browse files

Call WriteMessage directly in websocketconn.Conn.Write.

In the client←server direction, this hits a fast path that avoids
allocating a messageWriter.
https://github.com/gorilla/websocket/blob/v1.5.0/conn.go#L760

Cuts the number of allocations in half in the client←server direction:

	$ go test -bench=BenchmarkReadWrite -benchmem -benchtime=5s
	BenchmarkReadWrite/c←s_150-4              597511             13358 ns/op          11.23 MB/s       33709 B/op          2 allocs/op
	BenchmarkReadWrite/s←c_150-4              474176             13756 ns/op          10.90 MB/s       34968 B/op          4 allocs/op
	BenchmarkReadWrite/c←s_3000-4             156488             36290 ns/op          82.67 MB/s       68673 B/op          5 allocs/op
	BenchmarkReadWrite/s←c_3000-4             190897             34719 ns/op          86.41 MB/s       69730 B/op          8 allocs/op
parent c965d365
Loading
Loading
Loading
Loading
+5 −14
Original line number Diff line number Diff line
@@ -64,16 +64,7 @@ func writeLoop(ws *websocket.Conn, r io.Reader) error {
		if err != nil {
			return err
		}
		data := buf[:n]
		w, err := ws.NextWriter(websocket.BinaryMessage)
		if err != nil {
			return err
		}
		n, err = w.Write(data)
		if err != nil {
			return err
		}
		err = w.Close()
		err = ws.WriteMessage(websocket.BinaryMessage, buf[:n])
		if err != nil {
			return err
		}
@@ -100,10 +91,10 @@ func New(ws *websocket.Conn) *Conn {
	// https://godoc.org/github.com/gorilla/websocket#hdr-Concurrency
	// "Connections support one concurrent reader and one concurrent writer.
	// Applications are responsible for ensuring that no more than one
	// goroutine calls the write methods (NextWriter, etc.) concurrently and
	// that no more than one goroutine calls the read methods (NextReader,
	// etc.) concurrently. The Close and WriteControl methods can be called
	// concurrently with all other methods."
	// goroutine calls the write methods (WriteMessage, etc.) concurrently
	// and that no more than one goroutine calls the read methods
	// (NextReader, etc.) concurrently. The Close and WriteControl methods
	// can be called concurrently with all other methods."
	pr1, pw1 := io.Pipe()
	go func() {
		pw1.CloseWithError(closeErrorToEOF(readLoop(pw1, ws)))