You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于Go协程分批次执行并复用前序结果的技术咨询

分批次启动Goroutine:先完成父级数据获取,再处理子级数据

嘿,这事儿其实很好搞定!咱们核心就是要保证第一批goroutine全部执行完毕、收集好所有父级数据后,再启动第二批goroutine去处理子级数据。下面给你具体的实现思路和代码示例:

核心思路

  1. 用sync.WaitGroup等待第一批所有goroutine完成,收集它们返回的父级数据结果
  2. 基于第一批的结果,启动第二批goroutine,同样用WaitGroup等待所有子级任务完成
  3. 可以结合切片或通道传递第一批的结果,这里先给你最直观的切片实现,再补充通道优化方案

代码示例

假设你的Reddit订阅源包提供了GetParentFeed()方法获取单条父级数据,GetChildData(parentID string)方法根据父级ID获取子级数据:

package main

import (
    "fmt"
    "sync"
    // 导入你的Reddit订阅源包
    // "your/reddit/package"
)

// 定义父级数据结构,根据实际返回调整
type ParentFeed struct {
    ID    string
    Title string
    // 其他字段...
}

// 定义子级数据结构
type ChildData struct {
    ParentID string
    Content  string
    // 其他字段...
}

func main() {
    // ---------------------- 第一批:获取父级数据 ----------------------
    var parentWG sync.WaitGroup
    parentFeeds := make([]ParentFeed, 0)
    parentMu := sync.Mutex{} // 保护切片写入的互斥锁
    // 假设要获取5个父级订阅源(数量按需调整)
    parentCount := 5
    parentWG.Add(parentCount)

    // 启动第一批goroutine
    for i := 0; i < parentCount; i++ {
        go func(idx int) {
            defer parentWG.Done()
            // 调用Reddit包获取父级数据
            feed, err := reddit.GetParentFeed()
            if err != nil {
                fmt.Printf("获取第%d个父级数据失败:%v\n", idx, err)
                return
            }
            // 加锁写入结果切片,避免数据竞争
            parentMu.Lock()
            parentFeeds = append(parentFeeds, feed)
            parentMu.Unlock()
        }(i)
    }

    // 阻塞等待第一批所有goroutine完成
    parentWG.Wait()
    fmt.Printf("第一批任务完成,共获取%d条父级数据\n", len(parentFeeds))

    // ---------------------- 第二批:处理子级数据 ----------------------
    var childWG sync.WaitGroup
    childResults := make([]ChildData, 0)
    childMu := sync.Mutex{} // 保护子级结果切片的互斥锁
    childWG.Add(len(parentFeeds))

    // 遍历父级结果,启动第二批goroutine
    for _, feed := range parentFeeds {
        go func(parent ParentFeed) {
            defer childWG.Done()
            // 根据父级ID获取子级数据
            childData, err := reddit.GetChildData(parent.ID)
            if err != nil {
                fmt.Printf("获取父级[%s]的子级数据失败:%v\n", parent.Title, err)
                return
            }
            // 加锁写入子级结果切片
            childMu.Lock()
            childResults = append(childResults, childData)
            childMu.Unlock()
        }(feed)
    }

    // 等待第二批所有goroutine完成
    childWG.Wait()
    fmt.Printf("第二批任务完成,共获取%d条子级数据\n", len(childResults))

    // 后续可以继续处理子级数据...
}

优化方案:用通道替代互斥锁

如果不想用互斥锁,也可以用通道来安全传递第一批结果,代码会更简洁:

// 第一批改用通道收集结果
parentChan := make(chan ParentFeed, parentCount)
// 启动goroutine时将结果发送到通道
go func(idx int) {
    defer parentWG.Done()
    feed, err := reddit.GetParentFeed()
    if err == nil {
        parentChan <- feed
    }
}(i)

// 等待第一批完成后关闭通道
parentWG.Wait()
close(parentChan)

// 从通道读取所有父级结果
var parentFeeds []ParentFeed
for feed := range parentChan {
    parentFeeds = append(parentFeeds, feed)
}

这样就不用手动加锁,利用Go通道的特性天然避免了数据竞争。

内容的提问来源于stack exchange,提问作者Alex Kirwan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 09:00:00