Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

• Some guidelines are indeed strict

Slide 3

Slide 3 text

• Some guidelines are indeed strict • Most are not

Slide 4

Slide 4 text

• Some guidelines are indeed strict • Most are not • Use your own judgment

Slide 5

Slide 5 text

• Some guidelines are indeed strict • Most are not • Use your own judgment • But learn from best practices

Slide 6

Slide 6 text

Who am I

Slide 7

Slide 7 text

Who am I • Go programmer since r60

Slide 8

Slide 8 text

Who am I • Go programmer since r60 • m[k] = v, false

Slide 9

Slide 9 text

Who am I • Go programmer since r60 • m[k] = v, false • Go meetups and conferences organizer

Slide 10

Slide 10 text

Who am I • Go programmer since r60 • m[k] = v, false • Go meetups and conferences organizer • gophership.ru in 2 weeks

Slide 11

Slide 11 text

Who am I • Go programmer since r60 • m[k] = v, false • Go meetups and conferences organizer • gophership.ru in 2 weeks • golang-ru Slack admin

Slide 12

Slide 12 text

Who am I • Go programmer since r60 • m[k] = v, false • Go meetups and conferences organizer • gophership.ru in 2 weeks • golang-ru Slack admin • #school channel

Slide 13

Slide 13 text

How to Go Wrong with Concurrency Alexey Palazhchenko
 https://twitter.com/paaleksey

Slide 14

Slide 14 text

Concurrency axioms and theorems

Slide 15

Slide 15 text

Axioms

Slide 16

Slide 16 text

Axioms • A send to a full channel blocks • A receive from an empty channel blocks

Slide 17

Slide 17 text

Axioms • A send to a full channel blocks • A receive from an empty channel blocks • A send to a nil channel blocks forever • A receive from a nil channel blocks forever

Slide 18

Slide 18 text

Axioms • A send to a full channel blocks • A receive from an empty channel blocks • A send to a nil channel blocks forever • A receive from a nil channel blocks forever • A send to a closed channel panics • A receive from a closed channel returns the zero value immediately

Slide 19

Slide 19 text

Axioms • A send to a full channel blocks • A receive from an empty channel blocks • A send to a nil channel blocks forever • A receive from a nil channel blocks forever • A send to a closed channel panics • A receive from a closed channel returns the zero value immediately *That’s actually Dave Cheney, not me.

Slide 20

Slide 20 text

Theorems

Slide 21

Slide 21 text

Theorems • Closing the channel is a send-like communication from the senders to the receivers that there will be no more sends.

Slide 22

Slide 22 text

Theorems • Closing the channel is a send-like communication from the senders to the receivers that there will be no more sends. • It comes up repeatedly that people want to use close as a reverse signal from receivers to senders to say "stop sending to me". That is not what it means.

Slide 23

Slide 23 text

Theorems • Closing the channel is a send-like communication from the senders to the receivers that there will be no more sends. • It comes up repeatedly that people want to use close as a reverse signal from receivers to senders to say "stop sending to me". That is not what it means. *That’s actually Russ Cox, not me.

Slide 24

Slide 24 text

Theorems

Slide 25

Slide 25 text

• Do not use the same channel for both sends and receives in the same place. Theorems

Slide 26

Slide 26 text

• Do not use the same channel for both sends and receives in the same place. • Except for toy ping-pong examples. Theorems

Slide 27

Slide 27 text

• Do not use the same channel for both sends and receives in the same place. • Except for toy ping-pong examples. • And semaphores. Theorems

Slide 28

Slide 28 text

• Do not use the same channel for both sends and receives in the same place. • Except for toy ping-pong examples. • And semaphores. Theorems *That’s actually me this time!

Slide 29

Slide 29 text

• Do not use the same channel for both sends and receives in the same place. • Except for toy ping-pong examples. • And semaphores. Theorems *That’s actually me this time! **Maybe not

Slide 30

Slide 30 text

Fun practice

Slide 31

Slide 31 text

MySQL slowlog parser # Time: 131128 1:05:31
 # User@Host: user1[user1] @ localhost [127.0.0.1] Id: 69194
 # Schema: maindb Last_errno: 0 Killed: 0
 # Query_time: 0.000228 Rows_sent: 1 Rows_examined: 1
 # Bytes_sent: 545 Tmp_tables: 0 Tmp_disk_tables: 0 Tmp_table_sizes: 0
 # InnoDB_trx_id: 1A88583F
 # QC_Hit: No Full_scan: No Full_join: No Tmp_table: No
 # Log_slow_rate_type: query Log_slow_rate_limit: 2
 SET timestamp=1385600731;
 SELECT foo FROM bar WHERE id=1;

Slide 32

Slide 32 text

Initial parser type Event struct { // … } type Parser interface { Events() chan Event }

Slide 33

Slide 33 text

A better parser type Event struct { // … } type Parser interface { Events() <-chan Event }

Slide 34

Slide 34 text

An even better parser type Event struct { // … } type Parser interface { Events() <-chan *Event }

Slide 35

Slide 35 text

An even better parser type Event struct { Metrics map[string]float64 } type Parser interface { Events() <-chan *Event }

Slide 36

Slide 36 text

A good parser type Event struct { Metrics map[string]float64 } type Parser interface { Start(ctx context.Context) Events() <-chan *Event }

Slide 37

Slide 37 text

A great parser type Event struct { Metrics map[string]float64 } type Parser interface { Start(ctx context.Context, eventsCap int) Events() <-chan *Event }

Slide 38

Slide 38 text

A wonderful parser type Event struct { Metrics map[string]float64 Error error } type Parser interface { Start(ctx context.Context, eventsCap int) Events() <-chan *Event }

Slide 39

Slide 39 text

An awesome parser type Event struct { Metrics map[string]float64 Error error } type Parser interface { // Start starts parser in a separate goroutine. // Context cancelation starts parser shutdown. // Events channel is closed when a shutdown is complete. Start(ctx context.Context, eventsCap int) Events() <-chan *Event }

Slide 40

Slide 40 text

An perfect parser type Parser interface { // Start starts parser in a separate goroutine. // Context cancelation starts parser shutdown. // Events channel is closed when a shutdown is complete. Start(ctx context.Context, eventsCap int) // A parser is blocked when Events channel is full. Events() <-chan *Event }

Slide 41

Slide 41 text

Using our perfect parser func collect(ch <-chan *Event) { for event := range ch { // ... } }

Slide 42

Slide 42 text

Using our perfect (?) parser func collect(ch <-chan *Event) { for event := range ch { if fatal(event) { return } }

Slide 43

Slide 43 text

Using our no-so-perfect parser func collect(ch <-chan *Event) { defer func() { for range ch {} // drain }() for event := range ch { if fatal(event) { return } } }

Slide 44

Slide 44 text

Using our quite bad parser func collect(ch <-chan *Event) { defer func() { /* ... */ }() for event := range ch { if fatal(event) { // how to stop parser? return } } }

Slide 45

Slide 45 text

Using our ugly parser func collect(ch <-chan *Event, cancel context.CancelFunc) { defer func() { /* ... */ }() for event := range ch { if fatal(event) { cancel() return } } }

Slide 46

Slide 46 text

Using our ugly parser func collect(ch <-chan *Event, cancel context.CancelFunc) { defer func() { /* ... */ }() for event := range ch { if fatal(event) { // how to let caller know we stopped parser? cancel() return } } }

Slide 47

Slide 47 text

Can we do better?

Slide 48

Slide 48 text

What are we parsing anyway? # Time: 131128 1:05:31
 # User@Host: user1[user1] @ localhost [127.0.0.1] Id: 69194
 # Schema: maindb Last_errno: 0 Killed: 0
 # Query_time: 0.000228 Rows_sent: 1 Rows_examined: 1
 # Bytes_sent: 545 Tmp_tables: 0 Tmp_disk_tables: 0 Tmp_table_sizes: 0
 # InnoDB_trx_id: 1A88583F
 # QC_Hit: No Full_scan: No Full_join: No Tmp_table: No
 # Log_slow_rate_type: query Log_slow_rate_limit: 2
 SET timestamp=1385600731;
 SELECT foo FROM bar WHERE id=1;

Slide 49

Slide 49 text

What are we parsing anyway? • Two parts: block reader and block parser

Slide 50

Slide 50 text

What are we parsing anyway? • Two parts: block reader and block parser • No reason for the reader to be asynchronous

Slide 51

Slide 51 text

What are we parsing anyway? • Two parts: block reader and block parser • No reason for the reader to be asynchronous • For parser – maybe

Slide 52

Slide 52 text

Do we have to expose async API? • "Do not want to block the main thread"

Slide 53

Slide 53 text

Do we have to expose async API? • "Do not want to block the main thread" • There is no "main thread"

Slide 54

Slide 54 text

Do we have to expose async API? • "Do not want to block the main thread" • There is no "main thread" • "Pipelines a great and enable concurrency"

Slide 55

Slide 55 text

Do we have to expose async API? • "Do not want to block the main thread" • There is no "main thread" • "Pipelines a great and enable concurrency" • Sure, but they have downsides too

Slide 56

Slide 56 text

Do we have to expose async API? • "Do not want to block the main thread" • There is no "main thread" • "Pipelines a great and enable concurrency" • Sure, but they have downsides too • And do you really need concurrency?

Slide 57

Slide 57 text

The best API • The best exposed APIs are synchronous,
 hard to misuse, and boring

Slide 58

Slide 58 text

The best API • The best exposed APIs are synchronous,
 hard to misuse, and boring • Let caller decide if concurrency is desired

Slide 59

Slide 59 text

Boring practice

Slide 60

Slide 60 text

Reader type Reader interface { NextBlock() ([]string, error) Close() error }

Slide 61

Slide 61 text

Parser

Slide 62

Slide 62 text

Parser func Parse(block []string) (*Event, error) { // ... }

Slide 63

Slide 63 text

Stateful parser type Parser interface { NextEvent() (*Event, error) Close() error }

Slide 64

Slide 64 text

Real parser // NextEvent and Close can be called concurrently. type Parser interface { NextEvent() (*Event, error) Close() error }

Slide 65

Slide 65 text

The WORST parser type Parser interface { NextEvent() *Event // A caller should continue to call NextEvent // until error is returned. Close() error } func (p *SlowLogParser) NextEvent() *Event { return <-p.events }

Slide 66

Slide 66 text

How to go wrong with concurrency? • By using it where it is not needed

Slide 67

Slide 67 text

How to go wrong with concurrency? • By using it where it is not needed • "Concurrency Semantics" Workshop tickets are still on sale!

Slide 68

Slide 68 text

How to go wrong with concurrency? • By using it where it is not needed • "Concurrency Semantics" Workshop tickets are still on sale! • By exporting concurrent APIs where it is not needed

Slide 69

Slide 69 text

Are there exceptions?

Slide 70

Slide 70 text

Are there exceptions? • There are always exceptions

Slide 71

Slide 71 text

Are there exceptions? • There are always exceptions • When there are already async APIs

Slide 72

Slide 72 text

Are there exceptions? • There are always exceptions • When there are already async APIs • Avoid the worst variant

Slide 73

Slide 73 text

Are there exceptions? • There are always exceptions • When there are already async APIs • Avoid the worst variant • When you observe async events

Slide 74

Slide 74 text

Are there exceptions? • There are always exceptions • When there are already async APIs • Avoid the worst variant • When you observe async events • And don't want to poll

Slide 75

Slide 75 text

Are there exceptions? • There are always exceptions • When there are already async APIs • Avoid the worst variant • When you observe async events • And don't want to poll • For consistency with other APIs, time pressure, and other real-life events

Slide 76

Slide 76 text

How to go wrong with concurrency? • By using it where it is not needed • "Concurrency Semantics" Workshop tickets are still on sale! • By exporting concurrent APIs where it is not needed • By not thinking critically about it

Slide 77

Slide 77 text

Thank you Alexey Palazhchenko
 https://twitter.com/paaleksey

Slide 78

Slide 78 text

Extra links • Dave Cheney - Concurrency made easy • Dave Cheney - Practical Go: Real world advice for writing maintainable Go programs • Bob Nystrom - What Color is Your Function?