mirror of
https://github.com/teivah/100-go-mistakes.git
synced 2026-06-20 16:45:56 +08:00
init
This commit is contained in:
commit
3c419dace2
8 changed files with 1000231 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
.idea
|
||||||
|
*.out
|
||||||
|
100-go-mistakes.iml
|
||||||
2
README.md
Normal file
2
README.md
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
go test -bench=. -trace trace.out
|
||||||
|
go tool trace trace.out
|
||||||
161
concurrency/concurrency-not-magic.go
Normal file
161
concurrency/concurrency-not-magic.go
Normal file
|
|
@ -0,0 +1,161 @@
|
||||||
|
package concurrency
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"io"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type customer struct {
|
||||||
|
id string
|
||||||
|
firstName string
|
||||||
|
lastName string
|
||||||
|
ts time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseFile(reader *bufio.Reader) ([]customer, error) {
|
||||||
|
customers := make([]customer, 0)
|
||||||
|
for {
|
||||||
|
// Read a line
|
||||||
|
line, _, err := reader.ReadLine()
|
||||||
|
if err != nil {
|
||||||
|
switch err {
|
||||||
|
default:
|
||||||
|
return nil, err
|
||||||
|
case io.EOF:
|
||||||
|
// If io.EOF, we reached the end of the input
|
||||||
|
return customers, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Call parseLine and another customer
|
||||||
|
customers = append(customers, parseLine(string(line)))
|
||||||
|
}
|
||||||
|
return customers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseLine(line string) customer {
|
||||||
|
tokens := strings.Split(line, ",")
|
||||||
|
ts, _ := strconv.ParseInt(tokens[3], 10, 64)
|
||||||
|
return customer{
|
||||||
|
id: tokens[0],
|
||||||
|
firstName: tokens[1],
|
||||||
|
lastName: tokens[2],
|
||||||
|
ts: time.Unix(ts, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseFileWorker(reader *bufio.Reader) ([]customer, error) {
|
||||||
|
inputs := make(chan string, 1024)
|
||||||
|
results := make(chan customer, 1024)
|
||||||
|
customers := make([]customer, 0)
|
||||||
|
|
||||||
|
// Spin up multiple worker goroutines
|
||||||
|
workerWg := sync.WaitGroup{}
|
||||||
|
for i := 0; i < runtime.NumCPU(); i++ {
|
||||||
|
workerWg.Add(1)
|
||||||
|
go parseLineWorker(&workerWg, inputs, results)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gather
|
||||||
|
gatherWg := sync.WaitGroup{}
|
||||||
|
gatherWg.Add(1)
|
||||||
|
go func() {
|
||||||
|
for customer := range results {
|
||||||
|
customers = append(customers, customer)
|
||||||
|
}
|
||||||
|
gatherWg.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
// When workers are complete, we close the channel.
|
||||||
|
go func() {
|
||||||
|
workerWg.Wait()
|
||||||
|
close(results)
|
||||||
|
}()
|
||||||
|
|
||||||
|
loop:
|
||||||
|
for {
|
||||||
|
line, _, err := reader.ReadLine()
|
||||||
|
if err != nil {
|
||||||
|
switch err {
|
||||||
|
default:
|
||||||
|
return nil, err
|
||||||
|
case io.EOF:
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Scatter
|
||||||
|
inputs <- string(line)
|
||||||
|
}
|
||||||
|
close(inputs)
|
||||||
|
|
||||||
|
// Wait for the gather goroutine to complete.
|
||||||
|
gatherWg.Wait()
|
||||||
|
return customers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseLineWorker(wg *sync.WaitGroup, input <-chan string, output chan<- customer) {
|
||||||
|
for line := range input {
|
||||||
|
tokens := strings.Split(line, ",")
|
||||||
|
ts, _ := strconv.ParseInt(tokens[3], 10, 64)
|
||||||
|
output <- customer{
|
||||||
|
id: tokens[0],
|
||||||
|
firstName: tokens[1],
|
||||||
|
lastName: tokens[2],
|
||||||
|
ts: time.Unix(ts, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseFileGoroutines(reader *bufio.Reader) ([]customer, error) {
|
||||||
|
results := make(chan customer, 1024)
|
||||||
|
customers := make([]customer, 0)
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
|
||||||
|
loop:
|
||||||
|
for {
|
||||||
|
line, _, err := reader.ReadLine()
|
||||||
|
if err != nil {
|
||||||
|
switch err {
|
||||||
|
default:
|
||||||
|
return nil, err
|
||||||
|
case io.EOF:
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add 1 to the wait group
|
||||||
|
wg.Add(1)
|
||||||
|
// Spin up a new goroutine
|
||||||
|
go parseLineGoroutines(&wg, string(line), results)
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
// Wait for all the goroutines to complete before closing the channel
|
||||||
|
wg.Wait()
|
||||||
|
close(results)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Gather the results
|
||||||
|
for customer := range results {
|
||||||
|
customers = append(customers, customer)
|
||||||
|
}
|
||||||
|
|
||||||
|
return customers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseLineGoroutines(wg *sync.WaitGroup, line string, output chan<- customer) {
|
||||||
|
tokens := strings.Split(line, ",")
|
||||||
|
ts, _ := strconv.ParseInt(tokens[3], 10, 64)
|
||||||
|
output <- customer{
|
||||||
|
id: tokens[0],
|
||||||
|
firstName: tokens[1],
|
||||||
|
lastName: tokens[2],
|
||||||
|
ts: time.Unix(ts, 0),
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}
|
||||||
48
concurrency/concurrency-not-magic_test.go
Normal file
48
concurrency/concurrency-not-magic_test.go
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
package concurrency
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_parseFile(t *testing.T) {
|
||||||
|
file, err := os.Open("input.csv")
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer file.Close()
|
||||||
|
reader := bufio.NewReader(file)
|
||||||
|
|
||||||
|
customers, err := parseFile(reader)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, 1_000_000, len(customers))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Benchmark_parseFile(b *testing.B) {
|
||||||
|
benchmarkParseFile(b, parseFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Benchmark_parseFileWorker(b *testing.B) {
|
||||||
|
benchmarkParseFile(b, parseFileWorker)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Benchmark_parseFileGoroutines(b *testing.B) {
|
||||||
|
benchmarkParseFile(b, parseFileGoroutines)
|
||||||
|
}
|
||||||
|
|
||||||
|
func benchmarkParseFile(b *testing.B, f func(reader *bufio.Reader) ([]customer, error)) {
|
||||||
|
file, err := os.Open("input.csv")
|
||||||
|
require.NoError(b, err)
|
||||||
|
csv, _ := ioutil.ReadAll(file)
|
||||||
|
reader := bufio.NewReader(bytes.NewReader(csv))
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
f(reader)
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
concurrency/concurrency.test
Executable file
BIN
concurrency/concurrency.test
Executable file
Binary file not shown.
1000000
concurrency/input.csv
Normal file
1000000
concurrency/input.csv
Normal file
File diff suppressed because it is too large
Load diff
5
go.mod
Normal file
5
go.mod
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
module github.com/teivah/100-go-mistakes
|
||||||
|
|
||||||
|
go 1.15
|
||||||
|
|
||||||
|
require github.com/stretchr/testify v1.6.1
|
||||||
12
go.sum
Normal file
12
go.sum
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||||
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
Loading…
Reference in a new issue