面试题答案
一键面试任务分配
- 使用 goroutine 和 channel 实现任务队列:
- 创建一个任务结构体,例如:
type Task struct { ID int Payload interface{} }
- 定义一个全局的任务通道
taskChan
:
var taskChan = make(chan Task)
- 调度器(主 goroutine)负责将任务放入
taskChan
:
func scheduler() { for { // 假设从某个数据源获取任务 task := getTaskFromSource() taskChan <- task } }
- 工作节点(worker goroutine)从
taskChan
中取出任务并执行:
func worker(id int, taskChan chan Task) { for task := range taskChan { executeTask(task) } }
- 负载均衡:
- 可以使用诸如轮询的简单策略。例如,维护一个工作节点列表,按顺序将任务分配给每个工作节点。
var workers []*worker func distributeTasks() { workerIndex := 0 for task := range taskChan { workers[workerIndex].taskChan <- task workerIndex = (workerIndex + 1) % len(workers) } }
执行状态跟踪
- 任务状态结构体:
- 定义一个结构体来跟踪任务状态:
type TaskStatus struct { TaskID int Status string // 例如 "running", "completed", "failed" ErrorMsg string }
- 状态通道:
- 工作节点在任务执行完成后,通过一个状态通道
statusChan
将任务状态发送出去:
var statusChan = make(chan TaskStatus) func worker(id int, taskChan chan Task, statusChan chan TaskStatus) { for task := range taskChan { err := executeTask(task) status := TaskStatus{ TaskID: task.ID, Status: "completed", ErrorMsg: "", } if err!= nil { status.Status = "failed" status.ErrorMsg = err.Error() } statusChan <- status } }
- 调度器可以监听
statusChan
来更新任务状态信息:
func monitorStatus() { for status := range statusChan { updateTaskStatusInDB(status) } }
- 工作节点在任务执行完成后,通过一个状态通道
错误处理
- 任务执行错误:
- 在
executeTask
函数中,捕获并返回任务执行过程中的错误:
func executeTask(task Task) error { // 执行任务逻辑 if someErrorCondition { return fmt.Errorf("task execution error") } return nil }
- 在
- 系统错误:
- 例如网络错误、资源不足等。可以使用
sync
包中的工具来进行资源管理和错误处理。比如使用sync.Mutex
来保护共享资源,防止并发访问导致错误。 - 对于网络错误,在任务重试机制中,可以结合
time.Sleep
进行适当的重试间隔控制:
func executeTaskWithRetry(task Task, maxRetries int) error { for i := 0; i < maxRetries; i++ { err := executeTask(task) if err == nil { return nil } if isNetworkError(err) { time.Sleep(time.Second * time.Duration(i+1)) } else { return err } } return fmt.Errorf("max retries reached, task failed") }
- 例如网络错误、资源不足等。可以使用
可能遇到的挑战及解决方案
- 网络延迟和故障:
- 挑战:工作节点与调度器之间可能由于网络问题导致任务分配失败或状态更新丢失。
- 解决方案:引入心跳机制,工作节点定期向调度器发送心跳消息以确认连接状态。对于丢失的任务分配或状态更新,可以通过重试机制来解决。例如,调度器在一定时间内未收到工作节点的确认消息时,重新分配任务。
- 任务优先级:
- 挑战:如果任务有不同的优先级,简单的轮询分配策略无法满足需求。
- 解决方案:维护多个任务通道,每个通道对应不同的优先级。调度器根据任务优先级将任务放入相应的通道,工作节点根据自身能力和配置从不同优先级通道获取任务。
- 资源竞争:
- 挑战:多个工作节点可能同时访问共享资源,导致数据不一致或错误。
- 解决方案:使用
sync.Mutex
或sync.RWMutex
对共享资源进行保护。在访问共享资源前加锁,访问完成后解锁。还可以使用sync.Cond
进行条件变量控制,协调多个 goroutine 对共享资源的访问。