Lý do chính là chênh lệch chi phí gọi số bytes.HasPrefix()
và strings.HasPrefix()
. Như @tomasz đã chỉ ra trong nhận xét của mình, strings.HashPrefix()
được gạch chân theo mặc định trong khi bytes.HasPrefix()
thì không.
lý do tiếp theo là các loại thông số khác nhau: bytes.HasPrefix()
mất 2 lát (2 mô tả lát). strings.HasPrefix()
mất 2 chuỗi (2 chuỗi tiêu đề). Slice mô tả chứa một con trỏ và 2 int
s: chiều dài và năng lực, xem reflect.SliceHeader
. header chuỗi chỉ chứa một con trỏ và int
: chiều dài, xem reflect.StringHeader
.
Chúng tôi có thể chứng minh điều này nếu chúng tôi tự điền các hàm HasPrefix()
vào các hàm chuẩn, vì vậy, chúng tôi loại bỏ chi phí gọi (không bằng cả hai). Bằng cách nhấn mạnh chúng, sẽ không có cuộc gọi chức năng nào được thực hiện (đối với chúng).
HasPrefix()
triển khai:
// HasPrefix tests whether the byte slice s begins with prefix.
func HasPrefix(s, prefix []byte) bool {
return len(s) >= len(prefix) && Equal(s[0:len(prefix)], prefix)
}
// HasPrefix tests whether the string s begins with prefix.
func HasPrefix(s, prefix string) bool {
return len(s) >= len(prefix) && s[0:len(prefix)] == prefix
}
chức năng Benchmark sau nội tuyến họ:
func BenchmarkStrHasPrefix(b *testing.B) {
s, prefix := STR, PREFIX
for i := 0; i < b.N; i++ {
_ = len(s) >= len(prefix) && s[0:len(prefix)] == prefix
}
}
func BenchmarkBytHasPrefix(b *testing.B) {
s, prefix := STR_B, PREFIX_B
for i := 0; i < b.N; i++ {
_ = len(s) >= len(prefix) && bytes.Equal(s[0:len(prefix)], prefix)
}
}
Chạy các bạn sẽ có được kết quả rất chặt chẽ:
BenchmarkStrHasPrefix-2 300000000 5.88 ns/op
BenchmarkBytHasPrefix-2 200000000 6.17 ns/op
Lý do cho sự khác biệt nhỏ trong điểm chuẩn nội tuyến có thể là cả hai hàm đều kiểm tra prese nce của tiền tố bằng cách cắt các toán hạng string
và []byte
. Và kể từ khi string
s có thể so sánh trong khi byte lát không, BenchmarkBytHasPrefix()
đòi hỏi một cuộc gọi chức năng bổ sung cho bytes.Equal()
so với BenchmarkStrHasPrefix()
(và chức năng gọi thêm cũng bao gồm việc sao chép các thông số của nó: 2 header lát).
Những thứ khác có thể đóng góp một chút vào kết quả khác nhau ban đầu: đối số được sử dụng trong BenchmarkStrHasPrefix()
là hằng số, trong khi các tham số được sử dụng trong BenchmarkBytHasPrefix()
là các biến.
Bạn không nên lo lắng nhiều về sự khác biệt hiệu suất, cả hai chức năng hoàn chỉnh chỉ trong vài nano giây.
Lưu ý rằng "thực hiện" của bytes.Equal()
:
func Equal(a, b []byte) bool // ../runtime/asm_$GOARCH.s
Điều này có thể được inlined trong một số nền tảng dẫn đến không có chi phí cuộc gọi bổ sung.
các giá trị của 'STR',' STR_B', 'PREFIX',' PREFIX_B' là gì? –
@IsmailBadawi cập nhật ví dụ) – gobwas
lưu ý rằng trên Core2Duo P8600 của tôi cả hai điểm chuẩn đang thực hiện tương tự (~ 20 ns/op), trong khi trên i5-2400S chúng tương tự như của bạn - 5,5 vs 8.5 ns/op – tomasz