Slide 1

Slide 1 text

Golang Notes Traps that are not so obvious to beginners 19 May 2016 Tevin Zhang

Slide 2

Slide 2 text

Agenda Goroutine leak Slice V.S. Array Embedding V.S. Inheritance

Slide 3

Slide 3 text

Goroutine leak

Slide 4

Slide 4 text

Example Goroutine will hang forever if timeout f u n c m a i n ( ) { c h : = m a k e ( c h a n b o o l ) g o f u n c ( ) { d e f e r c l o s e ( c h ) / / d o s o m e t h i n g h e a v y c h < - t r u e / / s e n d r e s u l t } ( ) / / w a i t u n t i l t i m e o u t s e l e c t { c a s e r : = < - c h : p r i n t l n ( " T h e r e s u l t i s : " , r ) c a s e < - t i m e . A f t e r ( t i m e . S e c o n d ) : } } Run

Slide 5

Slide 5 text

Solution Add bu er to chan, or: f u n c s o l u t i o n 2 ( ) { c h : = m a k e ( c h a n b o o l ) g o f u n c ( ) { d e f e r c l o s e ( c h ) / / d o s o m e t h i n g h e a v y s e l e c t { c a s e c h < - t r u e : / / s e n d r e s u l t d e f a u l t : / / d o n o t h i n g i f n o b o d y ' s e x p e c t i n g i t } } ( ) / / w a i t u n t i l t i m e o u t s e l e c t { c a s e r : = < - c h : p r i n t l n ( " T h e r e s u l t i s : " , r ) c a s e < - t i m e . A f t e r ( t i m e . S e c o n d ) : } }

Slide 6

Slide 6 text

Keep in mind: Whenever you start a goroutine you need to know where it dies

Slide 7

Slide 7 text

Slices are naughty

Slide 8

Slide 8 text

What's the output? f u n c m a i n ( ) { s : = [ ] i n t { 1 } o n e : = & s [ 0 ] s = a p p e n d ( s , 2 ) f o r i : = r a n g e s { s [ i ] + + } p r i n t l n ( * o n e , s [ 0 ] , s [ 1 ] ) / / W h a t ' s t h e o u t p u t ? } Run

Slide 9

Slide 9 text

Empty page to avoid answer leak

Slide 10

Slide 10 text

Slice is not Array The size of an array is part of the type of array, thus xed Slice is not array, it's a descriptor of array It consists of a pointer to array( rst element), len, cap Append copies the underlying array when insu cient capacity is encountered

Slide 11

Slide 11 text

Internal of Array and Slice Array Slice

Slide 12

Slide 12 text

Slice to array s := make([]byte, 5) s = s[2:4]

Slide 13

Slide 13 text

What's the capacity of the slice? f u n c m a i n ( ) { s : = m a k e ( [ ] i n t , 5 1 2 ) f m t . P r i n t l n ( " L e n : " , l e n ( s ) , " C a p : " , c a p ( s ) ) s = a p p e n d ( s , 0 ) f m t . P r i n t l n ( " L e n : " , l e n ( s ) , " C a p : " , c a p ( s ) ) } Run

Slide 14

Slide 14 text

How about 1024 instead of 512? f u n c m a i n ( ) { s : = m a k e ( [ ] i n t , 1 0 2 4 ) f m t . P r i n t l n ( " L e n : " , l e n ( s ) , " C a p : " , c a p ( s ) ) s = a p p e n d ( s , 0 ) f m t . P r i n t l n ( " L e n : " , l e n ( s ) , " C a p : " , c a p ( s ) ) } Run

Slide 15

Slide 15 text

Slices grow

Slide 16

Slide 16 text

How / / g o 1 . 6 . 2 / s r c / r u n t i m e / s l i c e . g o / / g r o w s l i c e h a n d l e s s l i c e g r o w t h d u r i n g a p p e n d . / / I t i s p a s s e d t h e s l i c e t y p e , t h e o l d s l i c e , a n d t h e d e s i r e d n e w m i n i m u m c a p a c i t y , / / a n d i t r e t u r n s a n e w s l i c e w i t h a t l e a s t t h a t c a p a c i t y , w i t h t h e o l d d a t a / / c o p i e d i n t o i t . f u n c g r o w s l i c e ( t * s l i c e t y p e , o l d s l i c e , c a p i n t ) s l i c e { / / . . . f o r { i f o l d . l e n < 1 0 2 4 { n e w c a p + = n e w c a p } e l s e { n e w c a p + = n e w c a p / 4 } i f n e w c a p > = c a p { b r e a k } } / / . . . }

Slide 17

Slide 17 text

Keep in mind: Pre-allocate for better performance and less garbage

Slide 18

Slide 18 text

Slices change

Slide 19

Slide 19 text

While strings don't Copy happens during the conversion between [ ] b y t e and s t r i n g These are expensive: bytes = []byte(str) str = string(bytes)

Slide 20

Slide 20 text

Tips Avoid conversion as much as you could, or you make garbage lose performance Choose either [ ] b y t e or s t r i n g wisely There are H a s P r e f i x , T r i m S p a c e , S p l i t etc in the bytes package, just as in the strings package

Slide 21

Slide 21 text

Embedding is not inheritance and you may thought you know that

Slide 22

Slide 22 text

Inheritance in most OOL (e.g. Python)

Slide 23

Slide 23 text

Animal (Parent class): t y p e A n i m a l s t r u c t { } f u n c ( a * A n i m a l ) E a t ( ) { f m t . P r i n t l n ( " E a t i n g . . . " ) } f u n c ( a * A n i m a l ) F e e d ( ) { / / p r e p a r e f o o d a . E a t ( ) / / c l e a n u p }

Slide 24

Slide 24 text

Dog (Child of Animal): t y p e D o g s t r u c t { A n i m a l } f u n c ( d * D o g ) E a t ( ) { f m t . P r i n t l n ( " D o g e a t i n g . . . " ) } Let's see: f u n c m a i n ( ) { d : = D o g { } d . F e e d ( ) } Run

Slide 25

Slide 25 text

Why By embedding A n i m a l into D o g the only thing you got is D o g . F e e d ( ) and it doesn't work with D o g . E a t ( ) . There are NO relationships between A n i m a l and D o g , the A n i m a l don't know and can't reach the D o g In other words: You got nothing from embedding, it's just a syntactic sugar (in this case).

Slide 26

Slide 26 text

Embedding A.K.A. The golang style

Slide 27

Slide 27 text

Animal t y p e E a t e r i n t e r f a c e { E a t ( ) } t y p e A n i m a l s t r u c t { E a t e r } f u n c ( a * A n i m a l ) F e e d ( ) { / / p r e p a r e f o o d a . E a t e r . E a t ( ) / / c l e a n u p }

Slide 28

Slide 28 text

Dog (same as before) t y p e D o g s t r u c t { } f u n c ( d * D o g ) E a t ( ) { f m t . P r i n t l n ( " D o g e a t i n g . . . " ) } Here comes the di erence: f u n c m a i n ( ) { d : = A n i m a l { E a t e r : & D o g { } } d . F e e d ( ) } Run

Slide 29

Slide 29 text

Embedding is not Inheritance, not even close! Anonymous eld is just like ordinary one, nothing magic. There are NO relationships between the embedded eld and the enclosing struct, the former don't know the existance of the later thus can't reach to it.

Slide 30

Slide 30 text

Takeaways Slice is not array Pre-allocate for better performance and less garbage Avoid conversion between []byte and string, or you make garbage lose performance Whenever you start a goroutine you need to know where it dies Embedding is not Inheritance, use Interface

Slide 31

Slide 31 text

Thank you Tevin Zhang [email protected] (mailto:[email protected])

Slide 32

Slide 32 text

No content