Prealloc เป็นเครื่องมือวิเคราะห์แบบคงที่เพื่อค้นหาการประกาศชิ้นที่อาจเป็น preelocated
go install github.com/alexkohler/prealloc@latest
เช่นเดียวกับเครื่องมือการวิเคราะห์แบบคงที่ GO อื่น ๆ (เช่น Golint, Go Vet), prealloc สามารถเรียกใช้กับชื่อไฟล์หนึ่งชื่อหรือมากกว่าหนึ่งไฟล์หรือแพ็คเกจที่ชื่อโดยเส้นทางนำเข้า Prealloc ยังรองรับ ... Wildcard
prealloc [flags] files/directories/packages
ในขณะที่ GO พยายาม หลีกเลี่ยงการจัดสรรใหม่โดยการเพิ่มขีดความสามารถล่วงหน้าบางครั้งสิ่งนี้ไม่เพียงพอสำหรับชิ้นที่ยาวขึ้น หากขนาดของชิ้นเป็นที่รู้จักในเวลาที่สร้างมันควรจะระบุ
พิจารณาเกณฑ์มาตรฐานต่อไปนี้: (สามารถพบได้ใน prealloc_test.go ใน repo นี้)
import "testing"
func BenchmarkNoPreallocate ( b * testing. B ) {
existing := make ([] int64 , 10 , 10 )
b . ResetTimer ()
for i := 0 ; i < b . N ; i ++ {
// Don't preallocate our initial slice
var init [] int64
for _ , element := range existing {
init = append ( init , element )
}
}
}
func BenchmarkPreallocate ( b * testing. B ) {
existing := make ([] int64 , 10 , 10 )
b . ResetTimer ()
for i := 0 ; i < b . N ; i ++ {
// Preallocate our initial slice
init := make ([] int64 , 0 , len ( existing ))
for _ , element := range existing {
init = append ( init , element )
}
}
}$ go test -bench=. -benchmem
goos: linux
goarch: amd64
BenchmarkNoPreallocate-4 3000000 510 ns/op 248 B/op 5 allocs/op
BenchmarkPreallocate-4 20000000 111 ns/op 80 B/op 1 allocs/op อย่างที่คุณเห็นการไม่ตั้งล่วงหน้าอาจทำให้เกิดการทำงานได้เนื่องจากต้องไปที่อาร์เรย์พื้นฐานอีกครั้ง รูปแบบมาตรฐานด้านบนเป็นเรื่องธรรมดาใน GO: ประกาศชิ้นส่วนจากนั้นเขียนช่วงของช่วงหรือสำหรับลูปที่ผนวกหรือดัชนีเข้ามา จุดประสงค์ของเครื่องมือนี้คือการตั้งค่าสถานะการประกาศชิ้น/ลูปเช่นเดียวกับที่ใน BenchmarkNoPreallocate
ตัวอย่างบางส่วนจากแหล่งที่มา 1.9.2:
$ prealloc go/src/....
archive/tar/reader_test.go:854 Consider preallocating ss
archive/zip/zip_test.go:201 Consider preallocating all
cmd/api/goapi.go:301 Consider preallocating missing
cmd/api/goapi.go:476 Consider preallocating files
cmd/asm/internal/asm/endtoend_test.go:345 Consider preallocating extra
cmd/cgo/main.go:60 Consider preallocating ks
cmd/cgo/ast.go:149 Consider preallocating pieces
cmd/compile/internal/ssa/flagalloc.go:64 Consider preallocating oldSched
cmd/compile/internal/ssa/regalloc.go:719 Consider preallocating phis
cmd/compile/internal/ssa/regalloc.go:718 Consider preallocating oldSched
cmd/compile/internal/ssa/regalloc.go:1674 Consider preallocating oldSched
cmd/compile/internal/ssa/gen/rulegen.go:145 Consider preallocating ops
cmd/compile/internal/ssa/gen/rulegen.go:145 Consider preallocating ops
cmd/dist/build.go:893 Consider preallocating all
cmd/dist/build.go:1246 Consider preallocating plats
cmd/dist/build.go:1264 Consider preallocating results
cmd/dist/buildgo.go:59 Consider preallocating list
cmd/doc/pkg.go:363 Consider preallocating names
cmd/fix/typecheck.go:219 Consider preallocating b
cmd/go/internal/base/path.go:34 Consider preallocating out
cmd/go/internal/get/get.go:175 Consider preallocating out
cmd/go/internal/load/pkg.go:1894 Consider preallocating dirent
cmd/go/internal/work/build.go:2402 Consider preallocating absOfiles
cmd/go/internal/work/build.go:2731 Consider preallocating absOfiles
cmd/internal/objfile/pe.go:48 Consider preallocating syms
cmd/internal/objfile/pe.go:38 Consider preallocating addrs
cmd/internal/objfile/goobj.go:43 Consider preallocating syms
cmd/internal/objfile/elf.go:35 Consider preallocating syms
cmd/link/internal/ld/lib.go:1070 Consider preallocating argv
cmd/vet/all/main.go:91 Consider preallocating pp
database/sql/sql.go:66 Consider preallocating list
debug/macho/file.go:506 Consider preallocating all
internal/trace/order.go:55 Consider preallocating batches
mime/quotedprintable/reader_test.go:191 Consider preallocating outcomes
net/dnsclient_unix_test.go:954 Consider preallocating confLines
net/interface_solaris.go:85 Consider preallocating ifat
net/interface_linux_test.go:91 Consider preallocating ifmat4
net/interface_linux_test.go:100 Consider preallocating ifmat6
net/internal/socktest/switch.go:34 Consider preallocating st
os/os_windows_test.go:766 Consider preallocating args
runtime/pprof/internal/profile/filter.go:77 Consider preallocating lines
runtime/pprof/internal/profile/profile.go:554 Consider preallocating names
text/template/parse/node.go:189 Consider preallocating decl // cmd/api/goapi.go:301
var missing [] string
for feature := range optionalSet {
missing = append ( missing , feature )
}
// cmd/fix/typecheck.go:219
var b []ast. Expr
for _ , x := range a {
b = append ( b , x )
}
// net/internal/socktest/switch.go:34
var st [] Stat
sw . smu . RLock ()
for _ , s := range sw . stats {
ns := * s
st = append ( st , ns )
}
sw . smu . RUnlock ()
// cmd/api/goapi.go:301
var missing [] string
for feature := range optionalSet {
missing = append ( missing , feature )
} แม้ว่าขนาดของชิ้นส่วนจะถูกตั้งค่าไว้ก่อนมีขนาดเล็ก แต่ก็ยังมีประสิทธิภาพที่จะได้รับในการระบุความสามารถอย่างชัดเจนแทนที่จะปล่อยให้มันต่อ append เพื่อค้นพบว่าจำเป็นต้องตั้ง preallocate แน่นอนว่า preallocation ไม่จำเป็นต้องทำ ทุกที่ งานของเครื่องมือนี้เป็นเพียงเพื่อช่วยแนะนำสถานที่ที่ควรพิจารณา preallocating
ในระหว่างการประกาศชิ้นส่วนของคุณแทนที่จะใช้ค่าศูนย์ของชิ้นกับ var เริ่มต้นด้วย make ฟังก์ชั่นในตัวของ GO โดยผ่านประเภทและความยาวที่เหมาะสม ความยาวนี้โดยทั่วไปจะเป็นสิ่งที่คุณมีอยู่ การแก้ไขตัวอย่างจากด้านบนจะมีลักษณะเช่นนั้น:
// cmd/api/goapi.go:301
missing := make ([] string , 0 , len ( optionalSet ))
for feature := range optionalSet {
missing = append ( missing , feature )
}
// cmd/fix/typecheck.go:219
b := make ([]ast. Expr , 0 , len ( a ))
for _ , x := range a {
b = append ( b , x )
}
// net/internal/socktest/switch.go:34
st := make ([] Stat , 0 , len ( sw . stats ))
sw . smu . RLock ()
for _ , s := range sw . stats {
ns := * s
st = append ( st , ns )
}
sw . smu . RUnlock ()
// cmd/api/goapi.go:301
missing := make ([] string , 0 , len ( optionalSet ))
for feature := range optionalSet {
missing = append ( missing , feature )
} หมายเหตุ: หากประสิทธิภาพมีความสำคัญอย่างยิ่งอาจมีประสิทธิภาพมากขึ้นในการใช้ copy แทนที่จะ append สำหรับชิ้นขนาดใหญ่ สำหรับการอ้างอิงดูเกณฑ์มาตรฐานต่อไปนี้:
func BenchmarkSize200PreallocateCopy ( b * testing. B ) {
existing := make ([] int64 , 200 , 200 )
b . ResetTimer ()
for i := 0 ; i < b . N ; i ++ {
// Preallocate our initial slice
init := make ([] int64 , len ( existing ))
copy ( init , existing )
}
} $ go test -bench=. -benchmem
goos: linux
goarch: amd64
BenchmarkSize200NoPreallocate-4 500000 3080 ns/op 4088 B/op 9 allocs/op
BenchmarkSize200Preallocate-4 1000000 1163 ns/op 1792 B/op 1 allocs/op
BenchmarkSize200PreallocateCopy-4 2000000 807 ns/op 1792 B/op 1 allocs/op
ยินดีต้อนรับการร้องขอ!
หากคุณมีความสุขกับ prealloc ลองดูเครื่องมือวิเคราะห์แบบคงที่อื่น ๆ ของฉัน!