关于 go 协程的一个问题? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
Zach369
V2EX    Go 编程语言

关于 go 协程的一个问题?

  •  1
     
  •   Zach369 2020 年 7 月 23 日 3317 次点击
    这是一个创建于 2022 天前的主题,其中的信息可能已经有所发展或是发生改变。

    需求:

    fun main(){ x1(id string) (objectEntity entity, error) {} x2(id string) (objectEntity []entity, error) {} x3(id string) (objectEntity entity, error) {} } 

    x1(),x2(),x3()分别是三个互相不关联的 3 个 sql 查询. x1 会返回一个 objectEntity, error, x2 会返回一个[]objectEntity, x3 会返回一个 objectEntity. 我会拿到这 3 个返回值,然后进行拼接.
    本来直接使用 goroutine 和 channel 来进行请求. 但是我遇到一个问题, 不管是 x1,x2,x3 进行查询,返回值 都有 error. 大家有什么好的办法吗?

    17 条回复    2020-08-10 10:50:20 +08:00
    Immortal
        1
    Immortal  
       2020 年 7 月 23 日
    "不管是 x1,x2,x3 进行查询,返回值 都有 error" ???
    有 error 不就是报错了么,不能先处理了 error 再考虑后面拼接的问题么
    具体得看你们容错程度,一个或多个出错了就不参与拼接 还是 不能有 error 必须保证全部有结果才能拼接

    再另外说一句,既然要同步拼接,根本不需要走协程,同步执行就行了.异步反而更麻烦
    caryqy
        2
    caryqy  
       2020 年 7 月 23 日
    这个好像和协程没啥关系,要根据你需求来决定吧,比如某个返回值有 error 时用个默认值来代替
    Vegetable
        3
    Vegetable  
       2020 年 7 月 23 日
    再定义一个 channel 处理 error 呗
    KaynW
        4
    KaynW  
       2020 年 7 月 23 日
    搞不懂这为什么是协程的问题
    xmge
        5
    xmge  
       2020 年 7 月 23 日
    至少写个能跑起来的伪代码,让大家跑一下吧...... 要不大家都不知道你的代码是咋样的,也无法给你解决问题
    wangritian
        6
    wangritian  
       2020 年 7 月 23 日
    xResult {
    obj objectEntity
    err Error
    }
    不过我觉得这法子不太标准
    Zach369
        7
    Zach369  
    OP
       2020 年 7 月 23 日
    @Immortal 第一: 异步还是有必要的, 假如 x1 需要 0.5s x2 需要 0.5s x3 需要 0.8s. 如果同步执行,就需要 1.8s. 异步查询,0.8s 就可以拿到所有的结果. 第二: 查询有错误,是因为所有的 orm 包在查询的时候,都会返回 error 这个值. 我目前抽出来的函数 都没有直接对 error 进行处理.都是返回正常的结果和 error.然后在外层统一处理.
    vvmint233
        8
    vvmint233  
       2020 年 7 月 23 日
    把[]objectEntity 和 error 合成为一个结构体
    ```golang
    type A struct {
    list []objectEntity
    err error
    }
    ```
    然后错误逻辑放到 service 层做处理
    bruce0
        9
    bruce0  
       2020 年 7 月 23 日
    不管有没有协程,不都是应该先处理 error?
    只要 error 不是 nil
    直接返回给调用者处理就行了
    Zach369
        10
    Zach369  
    OP
       2020 年 7 月 23 日
    @all 我加了伪代码 求

    ```
    我加了伪代码... 求大家帮忙写个 gorouter

    ```
    func main() {
    id := 1
    user1, err := x1(id)
    if err != nil {
    // 处理
    }
    userList, err := x2(id)
    if err != nil {
    // 处理
    }
    user2, err := x3(id)
    if err != nil {
    // 处理
    }

    // 然后 user1, userList, user2 进行拼接
    }

    type User struct {
    Id int `json:"id"`
    Name string `json:"name"`
    }

    func x1(id int) (User, error) {
    var err error
    user := User{
    Id: 1,
    Name: "xx",
    }

    return user, err
    }

    func x2(id int) ([]User, error) {
    var err error
    user := User{
    Id: 1,
    Name: "xx",
    }
    userList := []User{user, user}

    return userList, err
    }

    func x3(id int) (User, error) {
    var err error
    var user User
    {
    }
    err = errors.New("假设出现错误")

    return user, err
    }

    ```

    ```
    Immortal
        11
    Immortal  
       2020 年 7 月 23 日
    @Zach369 #7
    我不知道你用的什么 orm 包,常用的 gorm 查询结果是不可能有 error 的,除非是查询结果不存在会有个"record not found"的 error

    异步这个你说的是对的,如果所有查询都正常的话.
    粗略想了下你要用 channel 需要就需要把结果和 error 统一包一个结构体.可能用 sync.WaitGroup 更简单一些.
    Zach369
        12
    Zach369  
    OP
       2020 年 7 月 23 日
    ```
    func main() {
    id := 1
    user1, err := x1(id)
    if err != nil {
    // 处理
    }
    userList, err := x2(id)
    if err != nil {
    // 处理
    }
    user2, err := x3(id)
    if err != nil {
    // 处理
    }

    // 然后 user1, userList, user2 进行拼接
    }

    type User struct {
    Id int `json:"id"`
    Name string `json:"name"`
    }

    func x1(id int) (User, error) {
    var err error
    user := User{
    Id: 1,
    Name: "xx",
    }

    return user, err
    }

    func x2(id int) ([]User, error) {
    var err error
    user := User{
    Id: 1,
    Name: "xx",
    }
    userList := []User{user, user}

    return userList, err
    }

    func x3(id int) (User, error) {
    var err error
    var user User
    {
    }
    err = errors.New("假设出现错误")

    return user, err
    }

    ```
    mengzhuo
        13
    mengzhuo  
       2020 年 7 月 23 日
    你这用 waitgroup 最合适了

    wg.Add(3)
    errCh := make(chan error)
    userCh := make(chan *User)

    go func(){
    defer wg.Done()
    user, err := x1()
    if err != nil {

    }
    }()
    icexin
        14
    icexin  
       2020 年 7 月 23 日
    Immortal
        15
    Immortal  
       2020 年 7 月 23 日
    tlday
        16
    tlday  
       2020 年 7 月 23 日
    根本原因还是 error 是什么,对于 error 应该怎么处理,因为三个 err 的含义或者容忍度可能不一样,一起处理感觉是在偷懒。你的问题跟 goroutine 没有什么关系。
    一起处理的话上面的那些 xxgroup 的例子可行,但是有点违背 go 的设计原则。因为本质上都是在“通过共享来传递消息”,通过共享几个 data 变量来在 routine 间传递消息不是 golang 推荐的做法。(我不确定现在 golang 还说不说这个设计理念了,好几年没写过 golang 了)
    BTW,我觉得你的数据库结构设计的可能有点问题,join 语句效率也没有低到这个程度吧,感觉你在强行拿 goroutine 做一个不必要的优化,“拿着锤子看什么都是钉子”系列。
    vvmint233
        17
    vvmint233  
       2020 年 8 月 10 日
    对此封了一个结构, 欢迎拍砖 https://github.com/mint-leaf/gotokit/tree/master/task
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1370 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 17:10 PVG 01:10 LAX 09:10 JFK 12:10
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86