前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go并发调用协程goroutine并通过管道chan收集返回值

Go并发调用协程goroutine并通过管道chan收集返回值

原创
作者头像
pooky
发布2020-10-30 16:06:55
7.7K2
发布2020-10-30 16:06:55
举报
文章被收录于专栏:开发随笔

这里整理一下go开发当中用到了并发协程多任务,同时收集返回多任务结果,go 协程没有直接返回,只能通过chan返回收集,其中用到几个特性

缓存管道是当满的时候是阻塞的,这个特性可以用到并发控制

需要用到&sync.WaitGroup{} 也就是说并发请求中的执行时间跟最长的有关,需要所有的计数器都消耗完了然后结束

第一种不用函数中统一返回,那么就用全局变量收集输出

代码语言:javascript
复制
package main

import (
    "fmt"
    "strconv"
    "sync"
    "time"
)

var responseChannel = make(chan string, 15)

func main() {
    fmt.Println(time.Now())
    go response()
    wg := &sync.WaitGroup{}
    //并发10
    limiter := make(chan bool, 10)
    for i := 0; i < 100; i++ {
        wg.Add(1)
        limiter <- true
        go httpGet(strconv.Itoa(i), limiter, wg)
    }
    wg.Wait()
    fmt.Println("all Done")
    fmt.Println(time.Now())
}

func httpGet(url string, limiter chan bool, wg *sync.WaitGroup) {

    defer wg.Done() //释放一个锁
    //do something
    time.Sleep(1 * time.Second)
    responseChannel <- fmt.Sprintf("Hello Go %s", url)
    <-limiter //释放一个hold
}
func response() {
    for rc := range responseChannel {
        fmt.Println("response:", rc)
    }
}

第二种:需要封装成一个函数的

代码语言:javascript
复制
package main

import (
    "fmt"
    "strconv"
    "sync"
    "time"
)

func httpGet(url string, response chan string, limiter chan bool, wg *sync.WaitGroup) {
    //计数器-1
    defer wg.Done()
    //coding do business
    time.Sleep(1 * time.Second)
    //结果数据传入管道
    response <- fmt.Sprintf("http get:%s", url)
    //释放一个并发
    <-limiter
}

func collect(urls []string) []string {
    var result []string
    //执行的 这里要注意  需要指针类型传入  否则会异常
    wg := &sync.WaitGroup{}
    //并发控制
    limiter := make(chan bool, 10)
    defer close(limiter)

    response := make(chan string, 20)
    wgResponse := &sync.WaitGroup{}
    //处理结果 接收结果
    go func() {
        wgResponse.Add(1)
        for rc := range response {
            result = append(result, rc)
        }
        wgResponse.Done()
    }()
    //开启协程处理请求
    for _, url := range urls {
        //计数器
        wg.Add(1)
        //并发控制 10
        limiter <- true
        go httpGet(url, response, limiter, wg)
    }
    //发送任务
    wg.Wait()
    close(response) //关闭 并不影响接收遍历
    //处理接收结果
    wgResponse.Wait()
    return result

}

func main() {
    var urls []string
    for i := 0; i < 100; i++ {
        urls = append(urls, strconv.Itoa(i))
    }
    fmt.Println(time.Now())
    result := collect(urls)
    fmt.Println(time.Now())
    fmt.Println(result)
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档