Vortrag der OOP 2014
Überblick über die Vorteile der Programmiersprache Go für skalierbare Anwendungen sowie ein Einblick in hierbei zu beachtende Probleme und ihre Lösung.
7. ❝
It’s better to have a permanent
income than to be fascinating.
–Oscar Wilde
8. Nebenläufigkeit in Go
•
Leichtgewichtige Goroutines im Thread
Pool
• Sehr große Anzahl gleichzeitig möglich
• Kommunikation und Synchronisation über
Channels
•
Vielfältige Kontrolle durch select
Statement
13. Kapselung in Typen
package service
!
type Service struct {
thisChan chan *This
thatChan chan *That
foo bool
bar int
baz string
}
14. Konstruktoren sind Funktionen
func NewService(...) *Service {
s := &Service{
thisChan: make(chan *This),
thatChan: make(chan *That, 10),
…,
}
!
// Start of the backend loop as goroutine.
go s.loop()
!
return s
}
15. Endlosschleifen und select
func (s *Service) loop() {
ticker := time.NewTicker(time.Second)
for {
select {
case this := <-s.thisChan:
s.doThis(this)
case that := <-s.thatChan:
s.doThat(that)
case <-ticker.C:
s.doTick()
}
}
}
16. Methoden als externe Schnittstellen
func (s *Service) DoThis(data string) int {
respChan := make(chan int)
this := &This{data, respChan}
!
s.thisChan <- this
return <-respChan
}
20. Sehr naive Parallelisierung (1)
func process(in []int) []int {
resultChan := make(chan int)
for _, value := range in {
// One goroutine per value.
go processValue(value, resultChan)
}
out := make([]int, 0)
for i := 0; i < len(in); i++ {
out = append(out, <-resultChan)
}
return out
}
21. Sehr naive Parallelisierung (2)
func processValue(
inValue int, resultChan chan int) {
// Time of result calculation depends
// on value.
outValue := inValue …
!
resultChan <- outValue
}
22. Verbesserung
•
• Output mit richtiger Größe initialisieren
Ergebnis gemäß Index setzen
•
Index in der Verarbeitung mitführen
23. Verbesserung (1)
func process(in []int) []int {
resultChan := make(chan *result)
for index, value := range in {
// One goroutine per value.
go processValue(index, value, resultChan)
}
out := make([]int, len(in))
for i := 0; i < len(in); i++ {
result <- resultChan
out[result.index] = result.value
}
return out
}
24. Verbesserung (2)
type result struct {
index int
value int
}
!
func processValue(
index, inValue int, resultChan chan *result) {
// Time of result calculation depends
// on value.
outValue := inValue …
!
// Send index with result.
resultChan <- &result{index, outValue}
}
25. Isolierung von Zugriffen
• Loops serialisieren Zugriffe
• Synchronisation über Channels oder
Package sync
• Referenzen nur an eine Goroutine senden
Aufteilung von Arrays und Slices
•
26. Unabhängigkeit von Goroutines
• Keine Beziehung zwischen Goroutines
Kontrolle nur über Channels
•
• Externe Packages helfen
git.tideland.biz/goas/loop
•
• launchpad.net/tomb
27. Schleifenfunktion
func (t *MyType) backendLoop(l loop.Loop) error {
for {
select {
case <-l.ShallStop():
return nil
case foo := <-t.fooChan:
if err := t.processFoo(foo); err != nil {
return err
}
case …:
…
}
}
}
28. Kontrolle der Schleifenfunktion
// Start of the goroutine in constructor.
t.loop = loop.Go(t.backendLoop)
!
// Tell loop to stop.
err := t.loop.Stop()
!
// Kill loop with passed error and wait.
t.loop.Kill(myError)
err := t.loop.Wait()
!
// Retrieve status and possible error.
status, err := t.loop.Error()
32. Hilfreiche Packages
• net, …/http für IP und Web
html/template, mime/… für Inhalte
•
• encoding/gob, …/json, …/xml für die
Serialisierung
• compress/… zur Komprimierung
• crypto/… zur Verschlüsselung
33. Externe Packages von Google
• WebSocket, SPDY, Dict und mehr in
code.google.com/p/go.net
• Weitere Crypto Packages (u.a. OpenPGP)
in code.google.com/p/go.crypto
34. Serialisierung via JSON
type OrderItem struct {
Id int `json:"ArticleNo"`
Quantity int
}
!
type Order struct {
Name string
Street string
City string
Remarks string `json:",omitempty"`
Items []OrderItem
}