MST

星途 面试题库

面试题:Go多值返回与并发编程的融合技巧

在一个高并发的Go应用程序中,有多个并发任务需要执行,每个任务会返回多个值(例如任务执行结果、执行时间、资源消耗等)。这些任务之间可能存在依赖关系,例如某些任务需要等待其他任务完成后才能执行。请设计一个基于Go多值返回和并发编程的架构来高效地管理这些任务,确保任务按照依赖关系正确执行,并能够正确处理和汇总所有任务的多值返回结果。描述你的设计思路,并给出关键部分的代码示例。
18.5万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 任务表示:使用结构体来表示每个任务,结构体中包含任务的执行函数、依赖任务的ID列表、任务执行结果的存储字段。
  2. 依赖管理:构建一个依赖关系图,通过任务ID来表示任务间的依赖。使用一个队列来存储没有依赖或依赖已满足的任务,逐步执行这些任务。
  3. 并发执行:利用Go的goroutine来并发执行任务。使用通道(channel)来传递任务的执行结果。
  4. 结果汇总:在所有任务执行完毕后,汇总每个任务的多值返回结果。

关键代码示例

package main

import (
    "fmt"
    "sync"
)

// Task 表示一个任务
type Task struct {
    ID       int
    Execute  func() (interface{}, int, int) // 返回执行结果、执行时间、资源消耗
    DependsOn []int
    Result    interface{}
    Time      int
    Resource  int
}

// TaskManager 管理任务的执行
type TaskManager struct {
    Tasks map[int]*Task
    WaitGroup sync.WaitGroup
}

// NewTaskManager 创建一个新的任务管理器
func NewTaskManager() *TaskManager {
    return &TaskManager{
        Tasks: make(map[int]*Task),
    }
}

// AddTask 添加一个任务
func (tm *TaskManager) AddTask(task *Task) {
    tm.Tasks[task.ID] = task
}

// ExecuteTasks 执行所有任务
func (tm *TaskManager) ExecuteTasks() {
    var readyQueue []*Task
    for _, task := range tm.Tasks {
        if len(task.DependsOn) == 0 {
            readyQueue = append(readyQueue, task)
        }
    }

    resultCh := make(chan *Task)
    defer close(resultCh)

    for len(readyQueue) > 0 {
        task := readyQueue[0]
        readyQueue = readyQueue[1:]

        tm.WaitGroup.Add(1)
        go func(t *Task) {
            defer tm.WaitGroup.Done()
            result, time, resource := t.Execute()
            t.Result = result
            t.Time = time
            t.Resource = resource
            resultCh <- t
        }(task)

        for _, newTask := range tm.Tasks {
            if contains(newTask.DependsOn, task.ID) {
                allDependsMet := true
                for _, depID := range newTask.DependsOn {
                    if tm.Tasks[depID].Result == nil {
                        allDependsMet = false
                        break
                    }
                }
                if allDependsMet {
                    readyQueue = append(readyQueue, newTask)
                }
            }
        }
    }

    go func() {
        tm.WaitGroup.Wait()
        close(resultCh)
    }()

    for result := range resultCh {
        fmt.Printf("Task %d executed. Result: %v, Time: %d, Resource: %d\n", result.ID, result.Result, result.Time, result.Resource)
    }
}

func contains(slice []int, item int) bool {
    for _, a := range slice {
        if a == item {
            return true
        }
    }
    return false
}

// 示例任务执行函数
func exampleExecute() (interface{}, int, int) {
    // 模拟任务执行
    return "Task result", 10, 50
}

func main() {
    tm := NewTaskManager()

    task1 := &Task{
        ID:       1,
        Execute:  exampleExecute,
        DependsOn: []int{},
    }
    task2 := &Task{
        ID:       2,
        Execute:  exampleExecute,
        DependsOn: []int{1},
    }

    tm.AddTask(task1)
    tm.AddTask(task2)

    tm.ExecuteTasks()
}

上述代码实现了一个简单的任务管理器,它能够处理任务间的依赖关系并并发执行任务,最后汇总每个任务的多值返回结果。在实际应用中,可根据具体需求进一步扩展和优化,例如任务执行函数的参数化、任务优先级处理等。