Introduction to go
- 2. Simple can be harder than complex
단 순 함 은 복 잡 함 보 다 어 렵 다 .
생 각 을 명 쾌 하 게 해 단 순 하 게 만 드 려 면 굉 장 히 노 력 해 야 한 다 .
하 지 만 결 국 그 럴 가 치 가 있 다 . 일 단 단 순 함 에 도 달 하 면 , 산 을 움 직 일 수 있 기 때 문 이 다 .
- 5. Why Go?
Statically typed languages ➔ Efficient vs Hard to write
Dynamic language ➔ Easy to use vs Slow
Speed vs Safety vs Ease to use
Concurrent programming is hard(thread, lock, mutex)
- 6. What is go
A modern, general purpose language.
open source
Statically typed languages
Feel dynamically
concurrents
garbage-collected
efficient
simply
- 8. 1. Object via struct and method
No Classes. No "Objects"
But Go is object-based
- 9. Object in Go
package main
import "fmt"
// Type Declaration (Struct)
type Rect struct {
width int
height int
}
// Declaring a Method
func (r *Rect) Area() int {
return r.width * r.height
}
// In Action
func main() {
r := Rect{width: 10, height: 5}
fmt.Println("area: ", r.Area())
} Run
- 10. Object in Go II
// Type Declaration (built-in type)
type Rects []Rect
// Declaring a Method
func (rs Rects) Area() int {
var a int
for _, r := range rs {
a += r.Area()
}
return a
}
// In Action
func main() {
r := Rect{width: 10, height: 5}
x := Rect{width: 7, height: 10}
rs := Rects{r, x}
fmt.Println("r's area: ", r.Area())
fmt.Println("x's area: ", x.Area())
fmt.Println("total area: ", rs.Area())
} Run
- 11. 2. Code reuse
No Inheritance
Composition over inheritance principle
- 12. Composition in Go
// Type Declaration (Struct)
type Address struct {
Number, Street, City, State string
}
// Embedding Types
type Person struct {
Name string
Address
}
func main() {
// Declare using Composite Literal
p := Person{
Name: "Steve",
Address: Address{Number: "13", Street: "Main", City: "Gotham", State: "NY"},
}
fmt.Println(p)
fmt.Println(p.Address)
} Run
- 13. Composition in Go II
// Declaring a Method
func (a *Address) String() string {
return a.Number + " " + a.Street + "n" + a.City + ", " + a.State + " " + "n"
}
func (p *Person) String() string {
return p.Name + "n" + p.Address.String()
}
func main() {
p := Person{
Name: "Steve",
Address: Address{Number: "13", Street: "Main", City: "Gotham", State: "NY"},
}
fmt.Println(p.String())
fmt.Println(p.Address.String())
} Run
- 14. 3. Polymorphism via interface
Interface is just set of methods
Interface define behavior (duck typing)
"If something can do this, then it can be used here"
- 15. Interfaces in Go
type Rect struct {
width int
height int
}
type Rects []Rect
func (r Rect) Area() int {
return r.width * r.height
}
func (rs Rects) Area() int {
var a int
for _, r := range rs {
a += r.Area()
}
return a
}
// Interface Declaration
type Shaper interface {
Area() int
}
- 16. Interfaces in Go II
// Interface Declaration
type Shaper interface {
Area() int
}
// Using Interface as Param Type
func Describe(s Shaper) {
fmt.Println("Area is:", s.Area())
}
// In Action
func main() {
r := Rect{width: 10, height: 5}
x := Rect{width: 7, height: 10}
rs := Rects{r, x}
Describe(r)
Describe(x)
Describe(rs)
} Run
- 17. The Power of Interface
Writer interface in standard "io" package
// http://godoc.org/io#Writer
type Writer interface {
Write(p []byte) (n int, err os.Error)
}
Fprintln function in standard "fmt" package
func Fprintln(w io.Writer, a ...interface{}) (n int, err error)
- 18. The Power of Interface
In handle function, just write to io.Writer object
func handle(w io.Writer, msg string) {
fmt.Fprintln(w, msg)
}
The os.Stdout can be used for io.Writer.
func main() {
msg := []string{"hello", "world", "this", "is", "an", "example", "of", "io.Writer"}
for _, s := range msg {
time.Sleep(100 * time.Millisecond)
handle(os.Stdout, s)
}
} Run
- 19. The Power of Interface
The http.ResponseWriter can be used for io.Writer.
func handle(w io.Writer, msg string) {
fmt.Fprintln(w, msg)
}
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
handle(w, r.URL.Path[1:])
})
fmt.Println("start listening on port 4000")
http.ListenAndServe(":4000", nil)
} Run
localhost:4000/hello-world (http://localhost:4000/hello-world)
localhost:4000/this-is-an-example-of-io.Writer (http://localhost:4000/this-is-an-example-of-io.Writer)
- 21. What is concurrency
Composition of independently executing computations.
It is not parallelism.
- 23. Go's approach
In UNIX: processes connected by pipes:
find ~/go/src | grep _test.go$ | xargs wc -l
In Go: goroutines connected by channels
- 24. Fundamentals #1 - Goroutine
Independently executing function.
The go statement launches a function call as a goroutine
go f()
go f(x, y, ...)
It's not a thread
Very lightweight
A goroutine has its own stack
A goroutine runs concurrently
- 25. Goroutine example
func f(msg string, delay time.Duration) {
for {
fmt.Println(msg)
time.Sleep(delay)
}
}
func main() {
go f("A--", 300*time.Millisecond)
go f("-B-", 500*time.Millisecond)
go f("--C", 1100*time.Millisecond)
time.Sleep(10 * time.Second)
} Run
- 26. Fundamentals #2 - Channel-based communication
Channel allow goroutines to exchange information and synchronize.
Define
chan int
chan<- string // send-only channel
<-chan T // receive-only channel
Create channel
ch = make(chan int)
Use
ch <- 1 // send value 1 on channel ch
x = <-ch // receive a value from channel ch
- 27. Communicating goroutines
func f(msg string, delay time.Duration, ch chan string) {
for {
ch <- msg
time.Sleep(delay)
}
}
func main() {
ch := make(chan string)
go f("A--", 300*time.Millisecond, ch)
go f("-B-", 500*time.Millisecond, ch)
go f("--C", 1100*time.Millisecond, ch)
for i := 0; i < 100; i++ {
fmt.Println(i, <-ch)
}
} Run
- 28. Communicating goroutines II
type Ball struct{ hits int }
func main() {
table := make(chan *Ball)
go player("ping", table)
go player("pong", table)
table <- new(Ball) // game on; toss the ball
time.Sleep(1 * time.Second)
<-table // game over; grab the ball
}
func player(name string, table chan *Ball) {
for {
ball := <-table
ball.hits++
fmt.Println(name, ball.hits)
time.Sleep(100 * time.Millisecond)
table <- ball
}
} Run
- 29. Philosophy
Goroutines give the efficiency of an asynchronous model.
But you can write code in a synchronous style.
"Don’t communicate by sharing memory . Instead, share memory by communicating."
- 33. Action of message processing worker
1. save message to datastore
2. fetch channel information
3. fetch user information
4. publish
- 36. Concurrency II
Run synchronously
err1 := msg.save()
c, err2 := msg.fetchChannel()
msg.setChannel(c)
u, err3 := msg.fetchUser()
msg.setUser(u)
if err1 != nil || err2 != nil || err3 != nil {
/* ... */
}
- 37. Concurrency III
Run concurrently
errc := make(chan error)
go func() {
err := msg.save()
errc <- err
}()
go func() {
c, err := msg.fetchChannel()
msg.setChannel(c)
errc <- err
}()
go func() {
u, err := msg.fetchUser()
msg.setUser(u)
errc <- err
}()
err1, err2, err3 := <-errc, <-errc, <- errc
if err1 != nil || err2 != nil || err3 != nil { /* ... */ }
- 39. Caching
Using SQL can be slow
Using redis is good, but fault tolerance is too hard.
Solution: Timeout waiting
- 40. Caching with control variance
func fetchUser(id string) (*User, error) {
var u *User
var err error
done := make(chan *User)
go func() {
u, _ := findFromRedis(id)
done <- u
}()
select {
case u = <-done:
case <-time.After(REDIS_TIMEOUT * time.Millisecond):
}
if u == nil {
u, err = findFromSql(id)
if err != nil {
return nil, err
}
saveToRedis(u)
}
return u, nil
}
- 45. Thank you
장재휴
Developer, Purpleworks
jaehue@jang.io (mailto:jaehue@jang.io)