рд╣реЗрд▓реЛ, рд╣реЗрдмреНрд░! рдореИрдВ рдЖрдкрдХреЗ рд▓рд┐рдП рдЙрджрдп рд╣рд┐рд░рд╡рд╛рд▓реЗ рдХреЗ рд▓реЗрдЦ "рдПрдирд╛рдЯреЙрдореА рдСрдлрд╝ рдЪреИрдирд▓реНрд╕ рдЗрди рдЧреЛ" рдХрд╛ рдЕрдиреБрд╡рд╛рдж рдкреНрд░рд╕реНрддреБрдд рдХрд░рддрд╛ рд╣реВрдБ ред
рдЪреИрдирд▓ рдХреНрдпрд╛ рд╣реИрдВ?
рдПрдХ рдЪреИрдирд▓ рдПрдХ рд╕рдВрдЪрд╛рд░ рд╡рд╕реНрддреБ рд╣реИ рдЬрд┐рд╕рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЧреЛрд░реЛрдЗрдВрдЯрд┐рди рдбреЗрдЯрд╛ рдХрд╛ рдЖрджрд╛рди-рдкреНрд░рджрд╛рди рдХрд░рддреЗ рд╣реИрдВред рддрдХрдиреАрдХреА рд░реВрдк рд╕реЗ, рдпрд╣ рдПрдХ рдХрдиреНрд╡реЗрдпрд░ (рдпрд╛ рдкрд╛рдЗрдк) рд╣реИ рдЬрд╣рд╛рдВ рд╕реЗ рдЖрдк рдбреЗрдЯрд╛ рдкрдврд╝ рдпрд╛ рдбрд╛рд▓ рд╕рдХрддреЗ рд╣реИрдВред рдпрд╣реА рд╣реИ, рдПрдХ рдЧреЛрд░реЛрдЗрди рдЪреИрдирд▓ рдХреЛ рдбреЗрдЯрд╛ рднреЗрдЬ рд╕рдХрддрд╛ рд╣реИ, рдФрд░ рджреВрд╕рд░рд╛ рдЗрд╕ рдЪреИрдирд▓ рдореЗрдВ рд░рдЦреЗ рдЧрдП рдбреЗрдЯрд╛ рдХреЛ рдкрдврд╝ рд╕рдХрддрд╛ рд╣реИред
рдЪреИрдирд▓ рдирд┐рд░реНрдорд╛рдг
рдЬрд╛рдУ рдЪреИрдирд▓ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЪрд╛рди рдХреАрд╡рд░реНрдб рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред рдПрдХ рдЪреИрдирд▓ рдХреЗрд╡рд▓ рдПрдХ рдкреНрд░рдХрд╛рд░ рдХрд╛ рдбреЗрдЯрд╛ рд╕рдВрдЪрд╛рд░рд┐рдд рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рдЕрдиреНрдп рдкреНрд░рдХрд╛рд░ рдХреЗ рдбреЗрдЯрд╛ рдХреЛ рдЗрд╕ рдЪреИрдирд▓ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдкреНрд░рд╕рд╛рд░рд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
package main
import "fmt"
func main() {
var c chan int
fmt.Println(c)
}
Play.golang.org рдкрд░ рдЙрджрд╛рд╣рд░рдг
c, int. <nil>, тАФ nil. . , (). make.
package main
import "fmt"
func main() {
c := make(chan int)
fmt.Printf("type of `c` is %T\n", c)
fmt.Printf("value of `c` is %v\n", c)
}
play.golang.org
:= make. :
type of `c` is chan int
value of `c` is 0xc0420160c0
c, . go . , , . , , .
Go <-
c <- data
c. , data c.
<- c
c. . , :
var data int
data = <- c
c, int, data. , :
data := <- c
Go , c, data .
. , , . , . , .
package main
import "fmt"
func greet(c chan string) {
fmt.Println("Hello " + <-c + "!")
}
func main() {
fmt.Println("main() started")
c := make(chan string)
go greet(c)
c <- "John"
fmt.Println("main() stopped")
}
play.golang.org
:
greet, c . c .main "main() started".- ,
make, c string. greet , go.main greet, main - .main , (greet) c. Go greet .main "main() stopped".
Deadlock ( )
, . , , "". deadlock, .
, , , - . : , .
deadlock main , .
package main
import "fmt"
func main() {
fmt.Println("main() started")
c := make(chan string)
c <- "John"
fmt.Println("main() stopped")
}
play.golang.org
:
main() started
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
program.go:10 +0xfd
exit status 2
Go , . , : val, ok := <- channel, ok , , ok false, . , close, close(channel). :
package main
import "fmt"
func greet(c chan string) {
<-c
<-c
}
func main() {
fmt.Println("main() started")
c := make(chan string, 1)
go greet(c)
c <- "John"
close(c)
c <- "Mike"
fmt.Println("main() stopped")
}
play.golang.org
c <- "John" , , greet . , c. , c , main close(c).
:
main() started
panic: send on closed channel
goroutine 1 [running]:
main.main()
program.go:20 +0x120
exit status 2
, , , . for.
for
package main
import "fmt"
func squares(c chan int) {
for i := 0; i <= 9; i++ {
c <- i * i
}
close(c)
}
func main() {
fmt.Println("main() started")
c := make(chan int)
go squares(c)
for {
val, ok := <-c
if ok == false {
fmt.Println(val, ok, "<-- loop broke!")
break
} else {
fmt.Println(val, ok)
}
}
fmt.Println("main() stopped")
}
play.golang.org
, . squares, 0 9. main for.
, val, ok := <-c, ok , . squares , , , close. ok true, val ( ok). ok false, , break. :
main() started
0 true
1 true
4 true
9 true
16 true
25 true
36 true
49 true
64 true
81 true
0 false <-- loop broke!
main() stopped
, val, , , . int, 0, : 0 false <-- loop broke!
, for, Go range, , . range:
package main
import "fmt"
func squares(c chan int) {
for i := 0; i <= 9; i++ {
c <- i * i
}
close(c)
}
func main() {
fmt.Println("main() started")
c := make(chan int)
go squares(c)
for val := range c {
fmt.Println(val)
}
fmt.Println("main() stopped")
}
play.golang.org
val := range c , range , . :
main() started
0
1
4
9
16
25
36
49
64
81
main() stopped
for range, - dealock .
, . make 2- . тАФ . - 0, . , , .
0, , . , , , , ( ). , , , , . , , .
:
c := make(chan Type, n)
Type n. , n+1 .
, , :
package main
import "fmt"
func squares(c chan int) {
for i := 0; i <= 3; i++ {
num := <-c
fmt.Println(num * num)
}
}
func main() {
fmt.Println("main() started")
c := make(chan int, 3)
go squares(c)
c <- 1
c <- 2
c <- 3
fmt.Println("main() stopped")
}
play.golang.org
c 3. , 3 (c <- 3), ( ), main , . :
main() started
main() stopped
:
package main
import "fmt"
func squares(c chan int) {
for i := 0; i <= 3; i++ {
num := <-c
fmt.Println(num * num)
}
}
func main() {
fmt.Println("main() started")
c := make(chan int, 3)
go squares(c)
c <- 1
c <- 2
c <- 3
c <- 4
fmt.Println("main() stopped")
}
play.golang.org
, main , squares, , .
, . тАФ ( ) , тАФ . , , len, , cap, .
package main
import "fmt"
func main() {
c := make(chan int, 3)
c <- 1
c <- 2
fmt.Printf("Length of channel c is %v and capacity of channel c is %v", len(c), cap(c))
fmt.Println()
}
play.golang.org
:
Length of channel c is 2 and capacity of channel c is 3
deadlock , 3, 2 , main. main, , .
:
package main
import "fmt"
func sender(c chan int) {
c <- 1
c <- 2
c <- 3
c <- 4
close(c)
}
func main() {
c := make(chan int, 3)
go sender(c)
fmt.Printf("Length of channel c is %v and capacity of channel c is %v\n", len(c), cap(c))
for val := range c {
fmt.Printf("Length of channel c after value '%v' read is %v\n", val, len(c))
}
}
play.golang.org
:
Length of channel c is 0 and capacity of channel c is 3
Length of channel c after value '1' read is 3
Length of channel c after value '2' read is 2
Length of channel c after value '3' read is 1
Length of channel c after value '4' read is 0
:
package main
import (
"fmt"
"runtime"
)
func squares(c chan int) {
for i := 0; i < 4; i++ {
num := <-c
fmt.Println(num * num)
}
}
func main() {
fmt.Println("main() started")
c := make(chan int, 3)
go squares(c)
fmt.Println("active goroutines", runtime.NumGoroutine())
c <- 1
c <- 2
c <- 3
c <- 4
fmt.Println("active goroutines", runtime.NumGoroutine())
go squares(c)
fmt.Println("active goroutines", runtime.NumGoroutine())
c <- 5
c <- 6
c <- 7
c <- 8
fmt.Println("active goroutines", runtime.NumGoroutine())
fmt.Println("main() stopped")
}
play.golang.org
:
main() started
active goroutines 2
1
4
9
16
active goroutines 1
active goroutines 2
25
36
49
64
active goroutines 1
main() stopped
for range, . , :
package main
import "fmt"
func main() {
c := make(chan int, 3)
c <- 1
c <- 2
c <- 3
close(c)
for elem := range c {
fmt.Println(elem)
}
}
play.golang.org
2 , , :
package main
import "fmt"
func square(c chan int) {
fmt.Println("[square] reading")
num := <-c
c <- num * num
}
func cube(c chan int) {
fmt.Println("[cube] reading")
num := <-c
c <- num * num * num
}
func main() {
fmt.Println("[main] main() started")
squareChan := make(chan int)
cubeChan := make(chan int)
go square(squareChan)
go cube(cubeChan)
testNum := 3
fmt.Println("[main] sent testNum to squareChan")
squareChan <- testNum
fmt.Println("[main] resuming")
fmt.Println("[main] sent testNum to cubeChan")
cubeChan <- testNum
fmt.Println("[main] resuming")
fmt.Println("[main] reading from channels")
squareVal, cubeVal := <-squareChan, <-cubeChan
sum := squareVal + cubeVal
fmt.Println("[main] sum of square and cube of", testNum, " is", sum)
fmt.Println("[main] main() stopped")
}
play.golang.org
:
- 2
square cube, . c c int, num. c. main squareChan cubeChan c int.square cube .- -
main testNum 3. squareChan cubeChan. main , . , .main (squareChan cubeChan), , (square cube) . := .- ,
main, .
:
[main] main() started
[main] sent testNum to squareChan
[cube] reading
[square] reading
[main] resuming
[main] sent testNum to cubeChan
[main] resuming
[main] reading from channels
[main] sum of square and cube of 3 is 36
[main] main() stopped
, . , . , , , .
make, .
roc := make(<-chan int)
soc := make(chan<- int)
roc , soc . , .
package main
import "fmt"
func main() {
roc := make(<-chan int)
soc := make(chan<- int)
fmt.Printf("Data type of roc is `%T`\n", roc)
fmt.Printf("Data type of soc is `%T\n", soc)
}
play.golang.org
:
Data type of roc is `<-chan int`
Data type of soc is `chan<- int
? e, , , .
, , , / . ?
Go .
import "fmt"
func greet(roc <-chan string) {
fmt.Println("Hello " + <-roc + "!")
}
func main() {
fmt.Println("main() started")
c := make(chan string)
go greet(c)
c <- "John"
fmt.Println("main() stopped")
}
play.golang.org
greet , . , :
"invalid operation: roc <- "some text" (send to receive-only type <-chan string)"
. , .
:
package main
import "fmt"
func main() {
fmt.Println("main() started")
c := make(chan string)
go func(c chan string) {
fmt.Println("Hello " + <-c + "!")
}(c)
c <- "John"
fmt.Println("main() stopped")
}
play.golang.org
.
, , , / . :
package main
import "fmt"
func greet(c chan string) {
fmt.Println("Hello " + <-c + "!")
}
func greeter(cc chan chan string) {
c := make(chan string)
cc <- c
}
func main() {
fmt.Println("main() started")
cc := make(chan chan string)
go greeter(cc)
c := <-cc
go greet(c)
c <- "John"
fmt.Println("main() stopped")
}
play.golang.org
select
select switch , . select , case.
, :
package main
import (
"fmt"
"time"
)
var start time.Time
func init() {
start = time.Now()
}
func service1(c chan string) {
time.Sleep(3 * time.Second)
c <- "Hello from service 1"
}
func service2(c chan string) {
time.Sleep(5 * time.Second)
c <- "Hello from service 2"
}
func main() {
fmt.Println("main() started", time.Since(start))
chan1 := make(chan string)
chan2 := make(chan string)
go service1(chan1)
go service2(chan2)
select {
case res := <-chan1:
fmt.Println("Response from service 1", res, time.Since(start))
case res := <-chan2:
fmt.Println("Response from service 2", res, time.Since(start))
}
fmt.Println("main() stopped", time.Since(start))
}
play.golang.org
select switch, , . select , default( ). case, main . case ?
case , select , case . , case ( : , ).
, . 2 . select c case . case chan1 chan2. , . case select , case .
select main ( ), select, service1 service2. service1 3 , chan1. service1 service2, 5 chan2. service1 , service2, case chan1, case . main, .
:
main() started 0s
Response from service 1 Hello from service 1 3s
main() stopped 3s
-, . , select, , , , .
, , case , Sleep .
package main
import (
"fmt"
"time"
)
var start time.Time
func init() {
start = time.Now()
}
func service1(c chan string) {
c <- "Hello from service 1"
}
func service2(c chan string) {
c <- "Hello from service 2"
}
func main() {
fmt.Println("main() started", time.Since(start))
chan1 := make(chan string)
chan2 := make(chan string)
go service1(chan1)
go service2(chan2)
select {
case res := <-chan1:
fmt.Println("Response from service 1", res, time.Since(start))
case res := <-chan2:
fmt.Println("Response from service 2", res, time.Since(start))
}
fmt.Println("main() stopped", time.Since(start))
}
play.golang.org
:
main() started 0s
service2() started 481┬╡s
Response from service 2 Hello from service 2 981.1┬╡s
main() stopped 981.1┬╡s
:
main() started 0s
service1() started 484.8┬╡s
Response from service 1 Hello from service 1 984┬╡s
main() stopped 984┬╡s
, chan1 chan2 , .
, case , .
package main
import (
"fmt"
"time"
)
var start time.Time
func init() {
start = time.Now()
}
func main() {
fmt.Println("main() started", time.Since(start))
chan1 := make(chan string, 2)
chan2 := make(chan string, 2)
chan1 <- "Value 1"
chan1 <- "Value 2"
chan2 <- "Value 1"
chan2 <- "Value 2"
select {
case res := <-chan1:
fmt.Println("Response from chan1", res, time.Since(start))
case res := <-chan2:
fmt.Println("Response from chan2", res, time.Since(start))
}
fmt.Println("main() stopped", time.Since(start))
}
play.golang.org
:
main() started 0s
Response from chan2 Value 1 0s
main() stopped 1.0012ms
:
main() started 0s
Response from chan1 Value 1 0s
main() stopped 1.0012ms
2. 2 , select. , , case , Go case .
default case
switch, select default. default , , default select . , ( ) .
- , select case. , default.
package main
import (
"fmt"
"time"
)
var start time.Time
func init() {
start = time.Now()
}
func service1(c chan string) {
fmt.Println("service1() started", time.Since(start))
c <- "Hello from service 1"
}
func service2(c chan string) {
fmt.Println("service2() started", time.Since(start))
c <- "Hello from service 2"
}
func main() {
fmt.Println("main() started", time.Since(start))
chan1 := make(chan string)
chan2 := make(chan string)
go service1(chan1)
go service2(chan2)
select {
case res := <-chan1:
fmt.Println("Response from service 1", res, time.Since(start))
case res := <-chan2:
fmt.Println("Response from service 2", res, time.Since(start))
default:
fmt.Println("No response received", time.Since(start))
}
fmt.Println("main() stopped", time.Since(start))
}
play.golang.org
:
main() started 0s
No response received 0s
main() stopped 0s
, , default. select default, .
default select , . main , time.Sleep. , main, .
package main
import (
"fmt"
"time"
)
var start time.Time
func init() {
start = time.Now()
}
func service1(c chan string) {
fmt.Println("service1() started", time.Since(start))
c <- "Hello from service 1"
}
func service2(c chan string) {
fmt.Println("service2() started", time.Since(start))
c <- "Hello from service 2"
}
func main() {
fmt.Println("main() started", time.Since(start))
chan1 := make(chan string)
chan2 := make(chan string)
go service1(chan1)
go service2(chan2)
time.Sleep(3 * time.Second)
select {
case res := <-chan1:
fmt.Println("Response from service 1", res, time.Since(start))
case res := <-chan2:
fmt.Println("Response from service 2", res, time.Since(start))
default:
fmt.Println("No response received", time.Since(start))
}
fmt.Println("main() stopped", time.Since(start))
}
play.golang.org
:
main() started 0s
service1() started 0s
service2() started 0s
Response from service 1 Hello from service 1 3.0001805s
main() stopped 3.0001805s
, :
main() started 0s
service1() started 0s
service2() started 0s
Response from service 2 Hello from service 2 3.0000957s
main() stopped 3.0000957s
Deadlock
, deadlock, default, , Go , .
package main
import (
"fmt"
"time"
)
var start time.Time
func init() {
start = time.Now()
}
func main() {
fmt.Println("main() started", time.Since(start))
chan1 := make(chan string)
chan2 := make(chan string)
select {
case res := <-chan1:
fmt.Println("Response from chan1", res, time.Since(start))
case res := <-chan2:
fmt.Println("Response from chan2", res, time.Since(start))
default:
fmt.Println("No goroutines available to send data", time.Since(start))
}
fmt.Println("main() stopped", time.Since(start))
}
play.golang.org
:
main() started 0s
No goroutines available to send data 0s
main() stopped 0s
, default, , ( ).
nil
, тАФ nil, - . select, .
package main
import "fmt"
func service(c chan string) {
c <- "response"
}
func main() {
fmt.Println("main() started")
var chan1 chan string
go service(chan1)
select {
case res := <-chan1:
fmt.Println("Response from chan1", res)
}
fmt.Println("main() stopped")
}
play.golang.org
:
main() started
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [select (no cases)]:
main.main()
program.go:17 +0xc0
goroutine 6 [chan send (nil chan)]:
main.service(0x0, 0x1)
program.go:6 +0x40
created by main.main
program.go:14 +0xa0
, select (no cases) , select , case . select{} main , service, nil , : chan send (nil chan). , , default.
package main
import "fmt"
func service(c chan string) {
c <- "response"
}
func main() {
fmt.Println("main() started")
var chan1 chan string
go service(chan1)
select {
case res := <-chan1:
fmt.Println("Response from chan1", res)
default:
fmt.Println("No response")
}
fmt.Println("main() stopped")
}
play.golang.org
:
main() started
No response
main() stopped
case , default . service. , , , , nil.
timeout
- , default . , , , default. , case , . After (package) time. :
package main
import (
"fmt"
"time"
)
var start time.Time
func init() {
start = time.Now()
}
func service1(c chan string) {
time.Sleep(3 * time.Second)
c <- "Hello from service 1"
}
func service2(c chan string) {
time.Sleep(5 * time.Second)
c <- "Hello from service 2"
}
func main() {
fmt.Println("main() started", time.Since(start))
chan1 := make(chan string)
chan2 := make(chan string)
go service1(chan1)
go service2(chan2)
select {
case res := <-chan1:
fmt.Println("Response from service 1", res, time.Since(start))
case res := <-chan2:
fmt.Println("Response from service 2", res, time.Since(start))
case <-time.After(2 * time.Second):
fmt.Println("No response received", time.Since(start))
}
fmt.Println("main() stopped", time.Since(start))
}
play.golang.org
2 :
main() started 0s
No response received 2s
main() stopped 2s
, <-time.After(2 * time.Second) main 2 . time.After , . chan1 chan2 , 3- , .
, . time.After(2 * time.Second) time.After(10 * time.Second) service1.
select
for{}, select{} , . select , case , select case, , , deadlock.
package main
import "fmt"
func service() {
fmt.Println("Hello from service!")
}
func main() {
fmt.Println("main() started")
go service()
select {}
fmt.Println("main() stopped")
}
play.golang.org
:
main() started
Hello from service!
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [select (no cases)]:
main.main()
program.go:16 +0xba
exit status 2
WaitGroup
, , ( : , ). , select. .
WaitGroup. , , ( : , , , , , , ). , .
:
package main
import (
"fmt"
"sync"
"time"
)
func service(wg *sync.WaitGroup, instance int) {
time.Sleep(2 * time.Second)
fmt.Println("Service called on instance", instance)
wg.Done()
}
func main() {
fmt.Println("main() started")
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
wg.Add(1)
go service(&wg, i)
}
wg.Wait()
fmt.Println("main() stopped")
}
play.golang.org
WaitGroup, noCopy state1 (https://golang.org/src/sync/waitgroup.go?s=574:929#L10). : Add, Wait Done. .
Add int , delta () WaitGroup. тАФ , 0. . WaitGroup , 0, , delta Add. , , , Add.
Wait , . 0, . - .
Done . . ( : sync, , Add(-1)).
, wg, for 1 3 . 1. 3 , WaitGroup 3. , wg . , Done , .
for, wg.Wait(), , , , main , , 0. main , .
:
main() started
Service called on instance 1
Service called on instance 3
Service called on instance 2
main() stopped
, - .
, тАФ , . WaitGroup , , . , - , .
package main
import (
"fmt"
"time"
)
func sqrWorker(tasks <-chan int, results chan<- int, id int) {
for num := range tasks {
time.Sleep(time.Millisecond)
fmt.Printf("[worker %v] Sending result by worker %v\n", id, id)
results <- num * num
}
}
func main() {
fmt.Println("[main] main() started")
tasks := make(chan int, 10)
results := make(chan int, 10)
for i := 0; i < 3; i++ {
go sqrWorker(tasks, results, i)
}
for i := 0; i < 5; i++ {
tasks <- i * 2
}
fmt.Println("[main] Wrote 5 tasks")
close(tasks)
for i := 0; i < 5; i++ {
result := <-results
fmt.Println("[main] Result", i, ":", result)
}
fmt.Println("[main] main() stopped")
}
play.golang.org
:
[main] main() started
[main] Wrote 5 tasks
[worker 0] Sending result by worker 0
[worker 2] Sending result by worker 2
[worker 1] Sending result by worker 1
[main] Result 0 : 4
[main] Result 1 : 0
[main] Result 2 : 16
[worker 2] Sending result by worker 2
[main] Result 3 : 64
[worker 0] Sending result by worker 0
[main] Result 4 : 36
[main] main() stopped
, , :
sqrWorker tasks, results, id. тАФ , tasks, results.main, tasks result , 10. , , . тАФ .sqrWorker id, , .- 5
tasks, , . tasks, . , , .for 5 , results. , . , , main .- , . ,
results, , , . , tasks. , tasks, for , tasks . deadlock, tasks . - ,
main , results . - , ,
main , results, .
, , . , . time.Sleep(), , , .
, .
WaitGroup . WaitGroup, , .
package main
import (
"fmt"
"sync"
"time"
)
func sqrWorker(wg *sync.WaitGroup, tasks <-chan int, results chan<- int, instance int) {
for num := range tasks {
time.Sleep(time.Millisecond)
fmt.Printf("[worker %v] Sending result by worker %v\n", instance, instance)
results <- num * num
}
wg.Done()
}
func main() {
fmt.Println("[main] main() started")
var wg sync.WaitGroup
tasks := make(chan int, 10)
results := make(chan int, 10)
for i := 0; i < 3; i++ {
wg.Add(1)
go sqrWorker(&wg, tasks, results, i)
}
for i := 0; i < 5; i++ {
tasks <- i * 2
}
fmt.Println("[main] Wrote 5 tasks")
close(tasks)
wg.Wait()
for i := 0; i < 5; i++ {
result := <-results
fmt.Println("[main] Result", i, ":", result)
}
fmt.Println("[main] main() stopped")
}
play.golang.org
:
[main] main() started
[main] Wrote 5 tasks
[worker 0] Sending result by worker 0
[worker 2] Sending result by worker 2
[worker 1] Sending result by worker 1
[worker 2] Sending result by worker 2
[worker 0] Sending result by worker 0
[main] Result 0 : 4
[main] Result 1 : 0
[main] Result 2 : 16
[main] Result 3 : 64
[main] Result 4 : 36
[main] main() stopped
, , results main , results - wg.Wait(). WaitGroup, () ( ), 7 9 . .
тАФ Go. , race condition( ). , . , , . , . :
package main
import (
"fmt"
"sync"
)
var i int
func worker(wg *sync.WaitGroup) {
i = i + 1
wg.Done()
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go worker(&wg)
}
wg.Wait()
fmt.Println("value of i after 1000 operations is", i)
}
play.golang.org
1000 , i, 0. WaitGroup, , 1000 i , , , 1000. main wg.Wait(), i. :
value of i after 1000 operations is 937
? 1000? . , , race condition. , .
i = i + 1 :
i- 1
i
, . , 2 1000 , . G1 G2.
G1 , i 0, i 1. , G1 i 1 3, G2 , . G2, i 0, i 1, G1 i 1. , 3- , 2 i 2, . , , i 1000.
, , , . i = i + 1 , Go ?
stackoverflow. Go .
, 3 , . тАФ , . , , , . , .
Go тАФ , sync. Go , race condition, , mutex.Lock(). i = i + 1 , , mutext.Unlock(). i , , . i. , , Lock Unlock, , .
, .
package main
import (
"fmt"
"sync"
)
var i int
func worker(wg *sync.WaitGroup, m *sync.Mutex) {
m.Lock()
i = i + 1
m.Unlock()
wg.Done()
}
func main() {
var wg sync.WaitGroup
var m sync.Mutex
for i := 0; i < 1000; i++ {
wg.Add(1)
go worker(&wg, &m)
}
wg.Wait()
fmt.Println("value of i after 1000 operations is", i)
}
, i, , m.Lock(), i , m.Unlock(). :
value of i after 1000 operations is 1000
, race condition. .
race condition Go, race, . go run -race program.go. .
, . , .
, . , . , , . , .
package main
import "fmt"
func fib(length int) <-chan int {
c := make(chan int, length)
go func() {
for i, j := 0, 1; i < length; i, j = i+j, i {
c <- i
}
close(c)
}()
return c
}
func main() {
for fn := range fib(10) {
fmt.Println("Current fibonacci number is", fn)
}
}
Current fibonacci number is 0
Current fibonacci number is 1
Current fibonacci number is 1
Current fibonacci number is 2
Current fibonacci number is 3
Current fibonacci number is 5
Current fibonacci number is 8
fib, , . fib, . . , . for, . main, range, , fib.
Fan-in Fan-out
Fan-in тАФ , . Fan-out тАФ , .
package main
import (
"fmt"
"sync"
)
func getInputChan() <-chan int {
input := make(chan int, 100)
numbers := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
go func() {
for num := range numbers {
input <- num
}
close(input)
}()
return input
}
func getSquareChan(input <-chan int) <-chan int {
output := make(chan int, 100)
go func() {
for num := range input {
output <- num * num
}
close(output)
}()
return output
}
func merge(outputsChan ...<-chan int) <-chan int {
var wg sync.WaitGroup
merged := make(chan int, 100)
wg.Add(len(outputsChan))
output := func(sc <-chan int) {
for sqr := range sc {
merged <- sqr
}
wg.Done()
}
for _, optChan := range outputsChan {
go output(optChan)
}
go func() {
wg.Wait()
close(merged)
}()
return merged
}
func main() {
chanInputNums := getInputChan()
chanOptSqr1 := getSquareChan(chanInputNums)
chanOptSqr2 := getSquareChan(chanInputNums)
chanMergedSqr := merge(chanOptSqr1, chanOptSqr2)
sqrSum := 0
for num := range chanMergedSqr {
sqrSum += num
}
fmt.Println("Sum of squares between 0-9 is", sqrSum)
}
.
chanInputNums, getInputChan. getInputChan , , , numbers .- (fan-out) (
chanOptSqr1 chanOptSqr2), getSquareChan. getSquareChan , , , . - (fan-in),
merge. merge WaitGroup, (merged), outputsChan, , , merged, , . . , . merged. - рд╣рдо
chanMergedSqrрдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЧрдП рдЪреИрдирд▓ рдХреЗ рдбреЗрдЯрд╛ рдХреЛ рдкрдврд╝рддреЗ рд╣реИрдВ forрдФрд░ rangeрдкреНрд░рд╛рдкреНрдд рдЖрдВрдХрдбрд╝реЛрдВ рдХреЛ рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ рдкреНрд░рд╕реНрддреБрдд рдХрд░рддреЗ рд╣реИрдВред - рдЕрдВрдд рдореЗрдВ, рд╣рдо рдЕрдкрдирд╛ рдкрд░рд┐рдгрд╛рдо рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВред
рдХрд╛рд░реНрдпрдХреНрд░рдо рдХрд╛ рдЖрдЙрдЯрдкреБрдЯ:
Sum of squares between 0-9 is 285
рдЕрдкрдбреЗрдЯ рдХрд░реЗрдВ:
рдЪреИрдирд▓ рдЗрдВрдЯрд░реНрдирд▓реНрд╕ рдкрд░ рдЖрдЧреЗ рдХрд╛ рд╕рд╛рд╣рд┐рддреНрдп:
- рдЧреЛ рдореЗрдВ рдЪреИрдирд▓реЛрдВ рдХреА рд╡реНрдпрд╡рд╕реНрдерд╛ рдХреИрд╕реЗ рдХреА рдЬрд╛рддреА рд╣реИ
- рдЧреЛрд▓рдВрдЧ рдХреЗ рд╣реБрдб рдХреЗ рддрд╣рдд - рдЪреИрдирд▓ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддреЗ рд╣реИрдВред рднрд╛рдЧ 1ред
- рдЧреЛрд▓рдВрдЧ рдореЗрдВ рдирд╣рд░ рдХреА рд╕рдВрд░рдЪрдирд╛ред рднрд╛рдЧ 2ред