Closed
Description
I have noticed Contains()
method leads its parameters to be allocated on the heap.
package main
import mapset "github.com/deckarep/golang-set/v2"
func main() {
a := mapset.NewSet[int]()
a.Contains(1)
}
Building the code above with go run -gcflags="-m" main.go
shows that Contains() parameter escapes to heap:
./main.go:7:12: ... argument escapes to heap
I forked the library and ran several benchmarks:
func BenchmarkContainsSlice(b *testing.B) {
slice := make([]int, 10000)
for i := 0; i < 10000; i++ {
slice[i] = i
}
set := mapset.NewThreadUnsafeSet[int](slice...)
for i := 0; i < b.N; i++ {
set.Contains(slice...)
}
}
func BenchmarkContainsVariadic(b *testing.B) {
slice := make([]int, 10000)
for i := 0; i < 10000; i++ {
slice[i] = i
}
set := mapset.NewThreadUnsafeSet[int](slice...)
for i := 0; i < b.N; i++ {
for i := 0; i < len(slice); i++ {
set.Contains(i)
}
}
}
And got the following results:
goos: darwin
goarch: arm64
pkg: variadic-escaping-test
BenchmarkContainsSlice
BenchmarkContainsSlice-10 6258 176586 ns/op 42 B/op 0 allocs/op
BenchmarkContainsVariadic
BenchmarkContainsVariadic-10 4209 277876 ns/op 80063 B/op 10000 allocs/op
I tried adding a new method which does not use variadic parameter:
type Set[T comparable] interface {
ContainsOne(val T) bool
}
func BenchmarkContainsNonVariadic(b *testing.B) {
slice := make([]int, 10000)
for i := 0; i < 10000; i++ {
slice[i] = i
}
a := mapset.NewThreadUnsafeSet[int](slice...)
for i := 0; i < b.N; i++ {
for i := 0; i < len(slice); i++ {
a.ContainsOne(i)
}
}
}
and got the following result for the new benchmark:
BenchmarkContainsNonVariadic
BenchmarkContainsNonVariadic-10 6762 170547 ns/op 39 B/op 0 allocs/op
- Is there a known fix for this problem?
- Should I open a PR to add the new method?
Metadata
Metadata
Assignees
Labels
No labels