MST
星途 面试题库

面试题:Go语言多返回值在并发编程中的复杂应用

假设有多个Go协程,每个协程处理不同的任务并返回不同类型的结果(例如,一个协程返回计算结果,另一个协程返回状态信息等)。请设计一个方案,使用Go语言的多返回值、通道(channel)以及同步机制(如sync.WaitGroup),将这些协程的结果收集并汇总,最后返回一个包含所有结果的结构体。详细说明在这个过程中如何处理协程间的同步、错误处理以及如何高效地整合多返回值。
41.1万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
package main

import (
    "fmt"
    "sync"
)

// 定义不同类型的结果结构体
type CalculationResult struct {
    Value int
}

type StatusInfo struct {
    Status string
}

// 定义最终汇总的结果结构体
type AllResults struct {
    Calculation CalculationResult
    Status      StatusInfo
}

func calculationTask() (CalculationResult, error) {
    // 模拟计算任务
    result := CalculationResult{Value: 42}
    return result, nil
}

func statusTask() (StatusInfo, error) {
    // 模拟状态任务
    status := StatusInfo{Status: "success"}
    return status, nil
}

func main() {
    var wg sync.WaitGroup
    calculationChan := make(chan CalculationResult, 1)
    statusChan := make(chan StatusInfo, 1)
    errorChan := make(chan error, 2)

    // 启动计算任务协程
    wg.Add(1)
    go func() {
        defer wg.Done()
        result, err := calculationTask()
        if err != nil {
            errorChan <- err
        } else {
            calculationChan <- result
        }
    }()

    // 启动状态任务协程
    wg.Add(1)
    go func() {
        defer wg.Done()
        status, err := statusTask()
        if err != nil {
            errorChan <- err
        } else {
            statusChan <- status
        }
    }()

    go func() {
        wg.Wait()
        close(calculationChan)
        close(statusChan)
        close(errorChan)
    }()

    var allResults AllResults
    var hasError bool

    for i := 0; i < 2; i++ {
        select {
        case result := <-calculationChan:
            allResults.Calculation = result
        case status := <-statusChan:
            allResults.Status = status
        case err := <-errorChan:
            fmt.Println("Error:", err)
            hasError = true
        }
    }

    if!hasError {
        fmt.Println("All results:", allResults)
    }
}
  1. 协程间同步
    • 使用 sync.WaitGroup 来等待所有协程完成。在启动每个协程前调用 wg.Add(1),在协程结束时调用 wg.Done()
    • 当所有协程都调用了 wg.Done() 后,通过一个独立的 go 协程关闭相关的通道,这样可以确保在所有协程完成后,通道关闭,不会出现死锁。
  2. 错误处理
    • 每个任务函数(如 calculationTaskstatusTask)返回结果的同时也返回错误。
    • 在协程内部,如果任务函数返回错误,将错误发送到 errorChan 通道。在主协程中,通过监听 errorChan 来处理错误。
  3. 多返回值整合
    • 为不同类型的结果创建不同的通道(如 calculationChanstatusChan)。
    • 每个协程将其结果发送到对应的通道。
    • 在主协程中,通过 select 语句监听不同的通道,将结果整合到 AllResults 结构体中。