Browse Source

Remove unnecessary *bytes.Reader in Stream.Write()

Prior to this change, each call to Stream.Write() would allocate 1 or
more *bytes.Reader instances. While these are small, it makes the Go
garbage collector do unnecessary work.

Besides the inefficiency at the machine level, it also makes no sense
at the human level to create an io.Reader and use io.Copy when a
single Write() call suffices.
Jacob Vosmaer 3 years ago
parent
commit
f4788e12b0
2 changed files with 6 additions and 6 deletions
  1. 4 4
      session.go
  2. 2 2
      stream.go

+ 4 - 4
session.go

@@ -80,7 +80,7 @@ type Session struct {
 // or to directly send a header
 // or to directly send a header
 type sendReady struct {
 type sendReady struct {
 	Hdr  []byte
 	Hdr  []byte
-	Body io.Reader
+	Body []byte
 	Err  chan error
 	Err  chan error
 }
 }
 
 
@@ -352,7 +352,7 @@ func (s *Session) keepalive() {
 }
 }
 
 
 // waitForSendErr waits to send a header, checking for a potential shutdown
 // waitForSendErr waits to send a header, checking for a potential shutdown
-func (s *Session) waitForSend(hdr header, body io.Reader) error {
+func (s *Session) waitForSend(hdr header, body []byte) error {
 	errCh := make(chan error, 1)
 	errCh := make(chan error, 1)
 	return s.waitForSendErr(hdr, body, errCh)
 	return s.waitForSendErr(hdr, body, errCh)
 }
 }
@@ -360,7 +360,7 @@ func (s *Session) waitForSend(hdr header, body io.Reader) error {
 // waitForSendErr waits to send a header with optional data, checking for a
 // waitForSendErr waits to send a header with optional data, checking for a
 // potential shutdown. Since there's the expectation that sends can happen
 // potential shutdown. Since there's the expectation that sends can happen
 // in a timely manner, we enforce the connection write timeout here.
 // in a timely manner, we enforce the connection write timeout here.
-func (s *Session) waitForSendErr(hdr header, body io.Reader, errCh chan error) error {
+func (s *Session) waitForSendErr(hdr header, body []byte, errCh chan error) error {
 	t := timerPool.Get()
 	t := timerPool.Get()
 	timer := t.(*time.Timer)
 	timer := t.(*time.Timer)
 	timer.Reset(s.config.ConnectionWriteTimeout)
 	timer.Reset(s.config.ConnectionWriteTimeout)
@@ -440,7 +440,7 @@ func (s *Session) send() {
 
 
 			// Send data from a body if given
 			// Send data from a body if given
 			if ready.Body != nil {
 			if ready.Body != nil {
-				_, err := io.Copy(s.conn, ready.Body)
+				_, err := s.conn.Write(ready.Body)
 				if err != nil {
 				if err != nil {
 					s.logger.Printf("[ERR] yamux: Failed to write body: %v", err)
 					s.logger.Printf("[ERR] yamux: Failed to write body: %v", err)
 					asyncSendErr(ready.Err, err)
 					asyncSendErr(ready.Err, err)

+ 2 - 2
stream.go

@@ -169,7 +169,7 @@ func (s *Stream) Write(b []byte) (n int, err error) {
 func (s *Stream) write(b []byte) (n int, err error) {
 func (s *Stream) write(b []byte) (n int, err error) {
 	var flags uint16
 	var flags uint16
 	var max uint32
 	var max uint32
-	var body io.Reader
+	var body []byte
 START:
 START:
 	s.stateLock.Lock()
 	s.stateLock.Lock()
 	switch s.state {
 	switch s.state {
@@ -195,7 +195,7 @@ START:
 
 
 	// Send up to our send window
 	// Send up to our send window
 	max = min(window, uint32(len(b)))
 	max = min(window, uint32(len(b)))
-	body = bytes.NewReader(b[:max])
+	body = b[:max]
 
 
 	// Send the header
 	// Send the header
 	s.sendHdr.encode(typeData, flags, s.id, max)
 	s.sendHdr.encode(typeData, flags, s.id, max)