面试题答案
一键面试1. 单向数据发送模式
在这种模式下,一个goroutine通过channel向另一个goroutine发送数据。
package main
import (
"fmt"
)
func sender(ch chan<- int) {
for i := 0; i < 5; i++ {
ch <- i
}
close(ch)
}
func main() {
ch := make(chan int)
go sender(ch)
for val := range ch {
fmt.Println(val)
}
}
在上述代码中,sender
函数向ch
这个单向发送的channel发送数据,主goroutine从该channel接收数据并打印。
2. 单向数据接收模式
与单向发送模式相反,一个goroutine从channel接收数据,另一个goroutine向该channel发送数据。
package main
import (
"fmt"
)
func receiver(ch <-chan int) {
for val := range ch {
fmt.Println(val)
}
}
func main() {
ch := make(chan int)
go func() {
for i := 0; i < 5; i++ {
ch <- i
}
close(ch)
}()
receiver(ch)
}
这里receiver
函数从单向接收的ch
channel接收数据,匿名goroutine向该channel发送数据。
3. 双向数据通信模式
两个goroutine之间可以通过同一个channel进行数据的发送和接收。
package main
import (
"fmt"
)
func talk(ch chan int) {
for i := 0; i < 3; i++ {
ch <- i
val := <-ch
fmt.Printf("Received %d back\n", val)
}
close(ch)
}
func main() {
ch := make(chan int)
go talk(ch)
for val := range ch {
newVal := val * 2
ch <- newVal
}
}
在talk
函数中,先向ch
发送数据,然后又从ch
接收数据。主goroutine从ch
接收数据并处理后再发回ch
。
4. 扇入(Fan - In)模式
多个goroutine向同一个channel发送数据,由一个goroutine从该channel接收数据。
package main
import (
"fmt"
)
func worker(id int, ch chan<- int) {
for i := 0; i < 3; i++ {
ch <- id*10 + i
}
close(ch)
}
func fanIn(inputs []<-chan int, output chan<- int) {
var wg sync.WaitGroup
for _, in := range inputs {
wg.Add(1)
go func(c <-chan int) {
defer wg.Done()
for val := range c {
output <- val
}
}(in)
}
go func() {
wg.Wait()
close(output)
}()
}
func main() {
var inputs []chan int
for i := 0; i < 2; i++ {
ch := make(chan int)
inputs = append(inputs, ch)
go worker(i, ch)
}
output := make(chan int)
fanIn(inputs, output)
for val := range output {
fmt.Println(val)
}
}
这里有多个worker
goroutine向不同的channel发送数据,fanIn
函数将这些channel的数据合并到一个输出channel。
5. 扇出(Fan - Out)模式
一个goroutine向多个channel发送数据,多个goroutine从这些不同的channel接收数据。
package main
import (
"fmt"
"sync"
)
func distributor(ch <-chan int, outputs []chan<- int) {
var wg sync.WaitGroup
for _, out := range outputs {
wg.Add(1)
go func(c chan<- int) {
defer wg.Done()
for val := range ch {
c <- val
}
close(c)
}(out)
}
go func() {
wg.Wait()
for _, out := range outputs {
close(out)
}
}()
for val := range ch {
for _, out := range outputs {
out <- val
}
}
close(ch)
}
func main() {
input := make(chan int)
var outputs []chan int
for i := 0; i < 2; i++ {
ch := make(chan int)
outputs = append(outputs, ch)
go func(id int, c <-chan int) {
for val := range c {
fmt.Printf("Worker %d received %d\n", id, val)
}
}(i, ch)
}
go func() {
for i := 0; i < 5; i++ {
input <- i
}
close(input)
}()
distributor(input, outputs)
}
distributor
函数将input
channel的数据分发给多个output
channel,不同的goroutine从各自的output
channel接收数据。