Last active
December 13, 2023 18:11
-
-
Save lesismal/a40c420511252aa79b054cbd2acc896e to your computer and use it in GitHub Desktop.
go net.Buffers vs user buffer append
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package test | |
import ( | |
"bufio" | |
"io" | |
"log" | |
"net" | |
"sync" | |
"testing" | |
"time" | |
) | |
var ( | |
listener net.Listener | |
headSize = 64 | |
bodySize = 1024 * 4 | |
totalSize = headSize + bodySize | |
loop = 100 | |
) | |
func startServer(addr string) { | |
if listener != nil { | |
return | |
} | |
var err error | |
listener, err = net.Listen("tcp", addr) | |
if err != nil { | |
log.Fatal(err) | |
} | |
go func() { | |
defer listener.Close() | |
for { | |
conn, err := listener.Accept() | |
if err != nil { | |
return | |
} | |
go func() { | |
defer conn.Close() | |
buf := make([]byte, totalSize) | |
for { | |
n, err := conn.Read(buf) | |
if err != nil { | |
return | |
} | |
conn.Write(buf[:n]) | |
} | |
}() | |
} | |
}() | |
time.Sleep(time.Second / 100) | |
} | |
func stopServer() { | |
listener.Close() | |
listener = nil | |
} | |
func BenchmarkNetBuffers(b *testing.B) { | |
addr := "127.0.0.1:8080" | |
startServer(addr) | |
defer stopServer() | |
b.ReportAllocs() | |
b.ResetTimer() | |
conn, err := net.Dial("tcp", addr) | |
if err != nil { | |
log.Fatal(err) | |
} | |
head := make([]byte, headSize) | |
body := make([]byte, bodySize) | |
buf := make([]byte, totalSize) | |
for i := 0; i < b.N; i++ { | |
for j := 0; j < loop; j++ { | |
buffers := net.Buffers([][]byte{head, body}) | |
nw, err := buffers.WriteTo(conn) | |
if err != nil { | |
b.Fatal(err) | |
} | |
n := int(nw) | |
if n != totalSize { | |
b.Fatalf("write less than totalSize") | |
} | |
n, err = io.ReadFull(conn, buf) | |
if err != nil { | |
b.Fatal(err) | |
} | |
if n != totalSize { | |
b.Fatalf("read less than totalSize") | |
} | |
} | |
} | |
} | |
func BenchmarkUserBuffers(b *testing.B) { | |
addr := "127.0.0.1:8081" | |
startServer(addr) | |
defer stopServer() | |
b.ReportAllocs() | |
b.ResetTimer() | |
conn, err := net.Dial("tcp", addr) | |
if err != nil { | |
log.Fatal(err) | |
} | |
pool := &sync.Pool{ | |
New: func() interface{} { | |
buf := make([]byte, totalSize) | |
return &buf | |
}, | |
} | |
head := make([]byte, headSize) | |
body := make([]byte, bodySize) | |
buf := make([]byte, totalSize) | |
for i := 0; i < b.N; i++ { | |
for j := 0; j < loop; j++ { | |
wbuf := (*pool.Get().(*[]byte))[:0] | |
wbuf = append(wbuf, head...) | |
wbuf = append(wbuf, body...) | |
n, err := conn.Write(wbuf) | |
if err != nil { | |
b.Fatal(err) | |
} | |
if n != totalSize { | |
b.Fatalf("write less than totalSize") | |
} | |
n, err = io.ReadFull(conn, buf) | |
if err != nil { | |
b.Fatal(err) | |
} | |
if n != totalSize { | |
b.Fatalf("read less than totalSize") | |
} | |
pool.Put(&wbuf) | |
} | |
} | |
} | |
func BenchmarkUserBuffersReuse(b *testing.B) { | |
addr := "127.0.0.1:8082" | |
startServer(addr) | |
defer stopServer() | |
b.ReportAllocs() | |
b.ResetTimer() | |
conn, err := net.Dial("tcp", addr) | |
if err != nil { | |
log.Fatal(err) | |
} | |
pool := &sync.Pool{ | |
New: func() interface{} { | |
buf := make([]byte, totalSize) | |
return &buf | |
}, | |
} | |
head := make([]byte, headSize) | |
body := make([]byte, bodySize) | |
buf := make([]byte, totalSize) | |
wbuf := make([]byte, totalSize) | |
for i := 0; i < b.N; i++ { | |
for j := 0; j < loop; j++ { | |
// copy(wbuf, head) | |
// copy(wbuf[len(head):], body) | |
wbuf = wbuf[:0] | |
wbuf = append(wbuf, head...) | |
wbuf = append(wbuf, body...) | |
n, err := conn.Write(wbuf) | |
if err != nil { | |
b.Fatal(err) | |
} | |
if n != totalSize { | |
b.Fatalf("write less than totalSize") | |
} | |
n, err = io.ReadFull(conn, buf) | |
if err != nil { | |
b.Fatal(err) | |
} | |
if n != totalSize { | |
b.Fatalf("read less than totalSize") | |
} | |
pool.Put(&wbuf) | |
} | |
} | |
} | |
func BenchmarkBufioWriter(b *testing.B) { | |
addr := "127.0.0.1:8083" | |
startServer(addr) | |
defer stopServer() | |
b.ReportAllocs() | |
b.ResetTimer() | |
conn, err := net.Dial("tcp", addr) | |
if err != nil { | |
log.Fatal(err) | |
} | |
head := make([]byte, headSize) | |
body := make([]byte, bodySize) | |
buf := make([]byte, totalSize) | |
writer := bufio.NewWriterSize(conn, totalSize) | |
for i := 0; i < b.N; i++ { | |
for j := 0; j < loop; j++ { | |
n1, err := writer.Write(head) | |
if err != nil { | |
b.Fatal(err) | |
} | |
n2, err := writer.Write(body) | |
if err != nil { | |
b.Fatal(err) | |
} | |
err = writer.Flush() | |
if err != nil { | |
b.Fatal(err) | |
} | |
n := n1 + n2 | |
if err != nil { | |
b.Fatal(err) | |
} | |
if n != totalSize { | |
b.Fatalf("write less than totalSize") | |
} | |
n, err = io.ReadFull(conn, buf) | |
if err != nil { | |
b.Fatal(err) | |
} | |
if n != totalSize { | |
b.Fatalf("read less than totalSize") | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
output: