Как постигаме паралелизъм в Go?
Какво е отношението между go рутини и нишки?
Каква е разликата между паралелизъм и конкурентност?
Как Дойчо ви препоръчва да изчакваме много go рутини да си свършат работата?
Какво става в go, когато всички go рутини блокират? Т.е. при deadblock?
type Cond struct {
// L is held while observing or changing the condition
L Locker
// contains filtered or unexported fields
}condition-variable или monitorsync, ако не можем да ползваме каналиmake
Операциите по изпращане и получаване се изпълняват с оператора <-
chan <- стойност изпраща по канала[променлива] <- chan получава от каналаКанал може да бъде затворен
intChannel := make(chan int)
stringBufferedChannel := make(chan string, 5)
readOnlyChannel := make(<-chan int)
writeOnlyChannel := make(chan<- int)
c := make(chan chan int)
func doSomething(input <-chan string) {}func doSomethingElse() chan string {
result := make(chan string)
return result
}Никога не използвайте неинициализиран канал!
package main
func main() {
var c chan string
c <- "ping" // deadlock
}package main
import "fmt"
func main() {
var c chan string
fmt.Println(<-c) // deadlock
}c := make(chan int)
go func() {
list.Sort()
c <- 1
}()
doSomethingForAWhile()
<-cvar sem = make(chan struct{}, MaxOutstanding)
func handle(r *Request) {
<-sem
process(r)
sem <- struct{}{}
}
func init() {
for i := 0; i < MaxOutstanding; i++ {
sem <- struct{}{}
}
}
func Serve(queue chan *Request) {
for {
req := <-queue
go handle(req)
}
}func main() {
c := make(chan int)
c <- 42
val := <-c
println(val)
}package main import "fmt" func main() { ch := make(chan string) go func(output chan string) { for i := 0; i < 5; i++ { output <- fmt.Sprintf("sending N=%d", i) } close(output) }(ch) for i := 0; i < 7; i++ { val, ok := <-ch fmt.Printf("Recieved: %#v, %#v\n", val, ok) } ch <- fmt.Sprintf("where is your towel?") }
Помните ли как ви казахме, че range е нещо супер яко?
for, когато каналът бъде затворенfor val := range ch {
fmt.Printf("Recieved: %#v\n", val)
}select {
case v1 := <-c1:
fmt.Printf("received %v from c1\n", v1)
case v2 := <-c2:
fmt.Printf("received %v from c2\n", v2)
default:
fmt.Printf("no one was ready to communicate\n")
}
Накратко: switch за канали.
Надълго: Изчаква първия канал, по който е изпратена стойност
defaultdefault блокира и изчакваselect {
case result := <-google:
fmt.Printf("received %v from google\n", result)
case result := <-bing:
fmt.Printf("received %v from bing\n", result)
case <- time.After(1 * time.Second):
fmt.Printf("timed out\n")
}
package main
import (
"fmt"
)
func f(left, right chan int) { left <- 1 + <-right } func main() { const n = 100000 leftmost := make(chan int) right := leftmost left := leftmost for i := 0; i < n; i++ { right = make(chan int) go f(left, right) left = right } go func(c chan int) { c <- 1 }(right) fmt.Println(<-leftmost) }
package main func fib() <-chan int { c := make(chan int) go func() { for a, b := 0, 1; ; a, b = b, a+b { c <- a } }() return c } func main() { fibonacci := fib() for i := 0; i < 10; i++ { println(<-fibonacci) } }
func talk(msg string) <-chan string { c := make(chan string) go func() { for i := 0; ; i++ { c <- fmt.Sprintf("%s: %d", msg, i) time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond) } }() return c }
package main
import (
"fmt"
"math/rand"
"time"
)
func main() { kiro := talk("Kiro") ned := talk("Ned") for i := 0; i < 5; i++ { fmt.Println(<-kiro) fmt.Println(<-ned) } }
// TALK START OMIT
func talk(msg string) <-chan string { // HL
c := make(chan string)
go func() {
for i := 0; ; i++ {
c <- fmt.Sprintf("%s: %d", msg, i)
time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
}
}()
return c
}
// TALK END OMIT
func fanIn(input1, input2 <-chan string) <-chan string { c := make(chan string) go func() { for { select { case s := <-input1: c <- s case s := <-input2: c <- s } } }() return c }
package main
import (
"fmt"
"math/rand"
"time"
)
// TALK START OMIT
func talk(msg string) <-chan string { // HL
c := make(chan string)
r := rand.New(rand.NewSource(time.Now().UnixNano()))
go func() {
for i := 0; ; i++ {
c <- fmt.Sprintf("%s: %d", msg, i)
time.Sleep(time.Duration(r.Intn(1e3)) * time.Millisecond)
}
}()
return c
}
// TALK END OMIT
// FANIN START OMIT
func fanIn(input1, input2 <-chan string) <-chan string { // HL
c := make(chan string)
go func() { // HL
for {
select { // HL
case s := <-input1:
c <- s // HL
case s := <-input2:
c <- s // HL
} // HL
}
}()
return c
}
// FANIN END OMIT
func main() { c := fanIn(talk("Ned"), talk("Kiril")) for i := 0; i < 10; i++ { fmt.Println(<-c) } }
func fanIn(input1, input2 <-chan string, finish chan struct{}) <-chan string { c := make(chan string) go func() { defer wg.Done() defer close(c) for { select { case s := <-input1: c <- s case s := <-input2: c <- s case <-finish: return } } }() return c }
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
var wg sync.WaitGroup
// TALK START OMIT
func talk(msg string) <-chan string { // HL
c := make(chan string)
r := rand.New(rand.NewSource(time.Now().UnixNano()))
go func() {
for i := 0; ; i++ {
c <- fmt.Sprintf("%s: %d", msg, i)
time.Sleep(time.Duration(r.Intn(1e3)) * time.Millisecond)
}
}()
return c
}
// TALK END OMIT
// FANIN START OMIT
func fanIn(input1, input2 <-chan string, finish chan struct{}) <-chan string { // HL
c := make(chan string)
go func() {
defer wg.Done()
defer close(c) // HL
for {
select {
case s := <-input1:
c <- s
case s := <-input2:
c <- s
case <-finish: // HL
return
}
}
}()
return c
}
// FANIN END OMIT
func main() { wg.Add(1) finish := make(chan struct{}) c := fanIn(talk("Ned"), talk("Kiril"), finish) for value := range c { fmt.Println(value) if len(value) > 8 { close(finish) } } wg.Wait() }