مرحبا يا هابر! أقدم لكم ترجمة مقال "تشريح القنوات في جو" لعدي هيوارالي.
ما هي القنوات؟
القناة هي كائن اتصال يتم من خلاله تبادل الغوروتين للبيانات. من الناحية الفنية ، هذا ناقل (أو أنبوب) يمكنك من خلاله قراءة البيانات أو وضعها. بمعنى أنه يمكن لرابط واحد أن يرسل البيانات إلى القناة ، والآخر يمكنه قراءة البيانات الموضوعة في هذه القناة.
إنشاء القناة
توفر Go الكلمة الأساسية chan لإنشاء قناة. يمكن للقناة إرسال بيانات من نوع واحد فقط ، ولا يمكن إرسال بيانات من أنواع أخرى من خلال هذه القناة.
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
تحديث:
المزيد من المؤلفات حول القنوات الداخلية:
- كيف يتم ترتيب القنوات في Go
- تحت غطاء Golang - كيف تعمل القنوات. الجزء الأول.
- هيكل القناة في جولانج. الجزء 2.