Merge branch 'pprof-allocs' into 'master'
Add allocs task See merge request slon/shad-go-private!33
This commit is contained in:
commit
8aff7885fa
4 changed files with 148 additions and 0 deletions
31
allocs/README.md
Normal file
31
allocs/README.md
Normal file
|
@ -0,0 +1,31 @@
|
|||
# allocs
|
||||
|
||||
`Counter` используется для нахождения уникальных слов и подсчета вхождений каждого из них.
|
||||
Его интерфейс выглядит так:
|
||||
|
||||
* `Count(r io.Reader) error` — функция, которая подсчитывает количество вхождений для каждого слова в тексте.
|
||||
На вход подается io.Reader, в котором находится некоторый текст.
|
||||
Разделителями являются только переносы строк и пробелы.
|
||||
* `String() string` — преобразует мапу вида `{"слово": "количество вхождений"}` в форматировнную строку.
|
||||
|
||||
Необходимо написать имплементацию `EnhancedCounter` (см. файл `allocs.go`)
|
||||
и снизить количество аллокаций. Бейзлайн можно найти в `baseline.go`.
|
||||
|
||||
Значения бенчмарков для бейзлайна:
|
||||
```
|
||||
goos: linux
|
||||
goarch: amd64
|
||||
pkg: gitlab.com/slon/shad-go/allocs
|
||||
Benchmark/count-4 73200 16294 ns/op 880 B/op 5 allocs/op
|
||||
Benchmark/main-4 40485 30113 ns/op 1034 B/op 9 allocs/op
|
||||
```
|
||||
|
||||
Значения бенчмарков для авторского решения:
|
||||
```goos: linux
|
||||
goarch: amd64
|
||||
pkg: gitlab.com/slon/shad-go/allocs
|
||||
Benchmark/count-4 212850 5471 ns/op 4144 B/op 2 allocs/op
|
||||
Benchmark/main-4 143937 8247 ns/op 4176 B/op 3 allocs/op
|
||||
```
|
||||
|
||||
|
9
allocs/allocs.go
Normal file
9
allocs/allocs.go
Normal file
|
@ -0,0 +1,9 @@
|
|||
// +build !solution
|
||||
|
||||
package allocs
|
||||
|
||||
// implement your Counter below
|
||||
|
||||
func NewEnhancedCounter() Counter {
|
||||
return NewBaselineCounter()
|
||||
}
|
52
allocs/allocs_test.go
Normal file
52
allocs/allocs_test.go
Normal file
|
@ -0,0 +1,52 @@
|
|||
package allocs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestCounter_Count(t *testing.T) {
|
||||
repeats := 10
|
||||
data := strings.Repeat("a b c\n", repeats)
|
||||
data = data[:len(data)-1]
|
||||
r := strings.NewReader(data)
|
||||
|
||||
c := NewEnhancedCounter()
|
||||
|
||||
err := c.Count(r)
|
||||
require.NoError(t, err)
|
||||
|
||||
expected := fmt.Sprintf("word 'a' has %d occurrences\n", repeats)
|
||||
expected += fmt.Sprintf("word 'b' has %d occurrences\n", repeats)
|
||||
expected += fmt.Sprintf("word 'c' has %d occurrences\n", repeats)
|
||||
actual := c.String()
|
||||
require.Equal(t, expected, actual)
|
||||
}
|
||||
|
||||
func Benchmark(b *testing.B) {
|
||||
repeats := 10000
|
||||
data := strings.Repeat("a b c d e f g h i j k l m n o p q r s t u v w x y z\n", repeats)
|
||||
data = data[:len(data)-1]
|
||||
|
||||
b.Run("count", func(b *testing.B) {
|
||||
r := strings.NewReader(data)
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
c := NewEnhancedCounter()
|
||||
_ = c.Count(r)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("main", func(b *testing.B) {
|
||||
r := strings.NewReader(data)
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
c := NewEnhancedCounter()
|
||||
_ = c.Count(r)
|
||||
_ = c.String()
|
||||
}
|
||||
})
|
||||
}
|
56
allocs/baseline.go
Normal file
56
allocs/baseline.go
Normal file
|
@ -0,0 +1,56 @@
|
|||
// +build !solution
|
||||
// +build !change
|
||||
|
||||
package allocs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Counter interface {
|
||||
Count(r io.Reader) error
|
||||
String() string
|
||||
}
|
||||
|
||||
type BaselineCounter struct {
|
||||
counts map[string]int
|
||||
}
|
||||
|
||||
func NewBaselineCounter() Counter {
|
||||
return BaselineCounter{counts: map[string]int{}}
|
||||
}
|
||||
|
||||
func (c BaselineCounter) Count(r io.Reader) error {
|
||||
data, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dataStr := string(data)
|
||||
for _, line := range strings.Split(dataStr, "\n") {
|
||||
for _, word := range strings.Split(line, " ") {
|
||||
c.counts[word]++
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c BaselineCounter) String() string {
|
||||
keys := make([]string, 0, 0)
|
||||
for word := range c.counts {
|
||||
keys = append(keys, word)
|
||||
}
|
||||
sort.Slice(keys, func(i, j int) bool {
|
||||
return keys[i] < keys[j]
|
||||
})
|
||||
|
||||
result := ""
|
||||
for _, key := range keys {
|
||||
line := fmt.Sprintf("word '%s' has %d occurrences\n", key, c.counts[key])
|
||||
result += line
|
||||
}
|
||||
return result
|
||||
}
|
Loading…
Reference in a new issue