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