面试题答案
一键面试扇入扇出模式维持稳定性的基本原理
- 扇出(Fan - out):
- 在高并发场景下,扇出是将一个输入源的数据分发给多个并发的处理单元。这有助于充分利用多核CPU的计算资源,提高处理速度。例如,在处理大量数据时,可以将数据分割成多个部分,每个部分交给一个独立的goroutine进行处理。这样可以并行处理数据,避免单个goroutine处理数据时可能出现的阻塞,从而提高系统的整体吞吐量。
- 扇入(Fan - in):
- 扇入是将多个并发处理单元的输出结果合并到一个输出通道。在高并发场景下,多个goroutine可能并行处理不同的数据块,扇入操作可以将这些分散的处理结果收集起来,进行统一的后续处理。它能确保所有处理结果都能被正确收集和处理,避免数据丢失,维持系统的稳定性。
通过通道实现简单的扇出操作代码示例
package main
import (
"fmt"
)
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
fmt.Printf("Worker %d started job %d\n", id, j)
result := j * 2 // 简单的处理逻辑,将输入翻倍
fmt.Printf("Worker %d finished job %d, result: %d\n", id, j, result)
results <- result
}
}
func main() {
const numJobs = 5
jobs := make(chan int, numJobs)
results := make(chan int, numJobs)
// 启动3个worker
const numWorkers = 3
for w := 1; w <= numWorkers; w++ {
go worker(w, jobs, results)
}
// 发送任务
for j := 1; j <= numJobs; j++ {
jobs <- j
}
close(jobs)
// 收集结果
for a := 1; a <= numJobs; a++ {
<-results
}
close(results)
}
在上述代码中:
worker
函数是一个goroutine,它从jobs
通道接收任务,处理后将结果发送到results
通道。- 在
main
函数中,创建了jobs
和results
通道,并启动了3个worker
goroutine。然后将5个任务发送到jobs
通道,最后从results
通道收集结果。这就是一个简单的扇出操作,一个输入源(jobs
通道)的数据被分发给多个worker
goroutine进行处理。
通过通道实现简单的扇入操作代码示例
package main
import (
"fmt"
)
func producer(id int, out chan<- int) {
for i := 1; i <= 3; i++ {
fmt.Printf("Producer %d sending %d\n", id, i)
out <- i * id
}
close(out)
}
func fanIn(input1, input2 <-chan int) <-chan int {
output := make(chan int)
go func() {
defer close(output)
for {
select {
case v, ok := <-input1:
if!ok {
return
}
output <- v
case v, ok := <-input2:
if!ok {
return
}
output <- v
}
}
}()
return output
}
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
go producer(1, ch1)
go producer(2, ch2)
result := fanIn(ch1, ch2)
for r := range result {
fmt.Println("Received:", r)
}
}
在这段代码中:
producer
函数模拟数据生产者,向各自的输出通道发送数据。fanIn
函数实现了扇入操作,它接收两个输入通道,通过select
语句从两个通道中接收数据,并将数据发送到一个统一的输出通道。main
函数中启动两个producer
goroutine,并调用fanIn
函数将它们的输出合并到一个通道中进行处理,这就是简单的扇入操作。