面试题答案
一键面试-
设计思路:
- 使用一个全局的
context.Context
来管理整个系统的生命周期。当接收到外部信号(如系统配置更新)时,取消这个context
。 - 每个微服务(
goroutine
)使用这个context
来判断是否应该停止发送数据。 - 使用
sync.WaitGroup
来等待所有微服务完成当前数据发送任务。 - 为每个
channel
设置一个“结束信号”机制,确保在所有数据发送完成后安全关闭channel
。
- 使用一个全局的
-
关键代码段及解释:
package main import ( "context" "fmt" "sync" "time" ) func main() { ctx, cancel := context.WithCancel(context.Background()) var wg sync.WaitGroup dataCh := make(chan int) // 模拟微服务1 wg.Add(1) go func(ctx context.Context, wg *sync.WaitGroup) { defer wg.Done() for { select { case <-ctx.Done(): return case dataCh <- 1: fmt.Println("Microservice 1 sent data") time.Sleep(time.Millisecond * 100) } } }(ctx, &wg) // 模拟微服务2 wg.Add(1) go func(ctx context.Context, wg *sync.WaitGroup) { defer wg.Done() for { select { case <-ctx.Done(): return case dataCh <- 2: fmt.Println("Microservice 2 sent data") time.Sleep(time.Millisecond * 100) } } }(ctx, &wg) // 模拟接收数据 go func() { for data := range dataCh { fmt.Println("Received data:", data) } fmt.Println("Data channel closed") }() // 模拟外部信号,500毫秒后取消context time.Sleep(time.Millisecond * 500) cancel() // 等待所有微服务完成任务 wg.Wait() close(dataCh) fmt.Println("System shut down") }
context.Context
相关代码:
这里创建了一个可取消的ctx, cancel := context.WithCancel(context.Background())
context
,ctx
用于传递取消信号给各个微服务,cancel
函数用于触发取消操作。- 微服务
goroutine
中的select
语句:select { case <-ctx.Done(): return case dataCh <- 1: fmt.Println("Microservice 1 sent data") time.Sleep(time.Millisecond * 100) }
select
语句用于监听ctx.Done()
信号,当接收到取消信号时,goroutine
会返回,停止向channel
发送数据。同时,它还继续向channel
发送数据,直到收到取消信号。 sync.WaitGroup
相关代码:var wg sync.WaitGroup wg.Add(1) go func(ctx context.Context, wg *sync.WaitGroup) { defer wg.Done() //... }(ctx, &wg)
wg.Add(1)
用于增加等待组的计数,每个微服务goroutine
启动时都增加计数。defer wg.Done()
在goroutine
结束时减少计数。wg.Wait()
用于阻塞主线程,直到所有微服务goroutine
完成任务。- 关闭
channel
代码:
在所有微服务完成任务后,关闭wg.Wait() close(dataCh)
channel
,避免资源泄漏,并保证数据一致性,因为所有数据都已经发送完成。
-
避免资源泄漏和保证数据一致性:
- 避免资源泄漏:通过
context
来控制goroutine
的生命周期,确保在接收到取消信号后,goroutine
能正确退出,不会造成goroutine
泄漏。在所有goroutine
完成任务后关闭channel
,避免channel
一直处于打开状态造成资源浪费。 - 保证数据一致性:每个微服务在接收到取消信号前,会继续完成当前的数据发送任务。
sync.WaitGroup
确保所有微服务都完成任务后才关闭channel
,这样保证了所有数据都能被正确发送和接收,从而保证数据一致性。
- 避免资源泄漏:通过