紫⾊飞猪的研发之旅--09go协程返回值的问题处理
在实际go开发中,需要充分的利⽤go的语⾔特⾊,开启适当的goroutine,对于所需的返回值的处理,成为⽐较有意思的问题,困扰很久,终于解决。
执⾏go协程时, 是没有返回值的, 这时候需要⽤到go语⾔中特⾊的channel来获取到返回值. 通过channel拿到返回值有两种处理形式, ⼀种形式是具有go风格特⾊的, 即发送给⼀个for channel或lect channel的独⽴goroutine中, 由该独⽴的goroutine来处理函数的返回值. 还有⼀种传统的做法, 就是将所有goroutine的返回值都集中到当前函数, 然后统⼀返回给调⽤函数.
发送给独⽴的goroutine处理程序
package main
import (
"fmt"
"sync"
"time"
)
var responChannel = make(chan string, 15)
func httpGet(url int, limiter chan bool, wg *sync.WaitGroup) {
// 函数执⾏完毕时计数器-1
defer wg.Done()
fmt.Println("http get:", url)
responChannel <- fmt.Sprintf("Hello Go %d", url)
// 释放⼀个坑位
<- limiter
}
func ResponController() {
for rc := range responChannel {
fmt.Println("respon: ", rc)
}
}
func main() {
// 启动接收respon的控制器
go ResponController()
wg := &sync.WaitGroup{}
// 控制并发数为10
limiter := make(chan bool, 20)
for i := 0; i < 99; i++ {
/
/ 计数器+1
wg.Add(1)
limiter <- true
go httpGet(i, limiter, wg)
}
// 等待所以协程执⾏完毕
wg.Wait() // 当计数器为0时, 不再阻塞
骂人的话英文fmt.Println("所有协程已执⾏完毕")
noveli}
这种具有Go语⾔特⾊的处理⽅式的关键在于, 你需要预先创建⼀个⽤于处理返回值的公共管道. 然后定义⼀个⼀直在读取该管道的函数, 该函数需要预先以单独的goroutine形式启动.
最后当执⾏到并发任务时, 每个并发任务得到结果后, 都会将结果通过管道传递到之前预先启动的goroutine中.
在当前函数中聚合返回
package main
import (
"fmt"
asmuchas"sync"
)
func httpGet(url int,respon chan string, limiter chan bool, wg *sync.WaitGroup) {
melissa smith
// 函数执⾏完毕时计数器-1
defer wg.Done()
// 将拿到的结果, 发送到参数中传递过来的channel中
respon <- fmt.Sprintf("http get: %d", url)
// 释放⼀个坑位
<- limiter
}
grenoble// 将所有的返回结果, 以 []string 的形式返回
func collect(urls []int) []string {
var result []string
wg := &sync.WaitGroup{}
// 控制并发数为10
limiter := make(chan bool, 5)
defer clo(limiter)
2018考研英语答案/
/ 函数内的局部变量channel, 专门⽤来接收函数内所有goroutine的结果
responChannel := make(chan string, 20)
// 为读取结果控制器创建新的WaitGroup, 需要保证控制器内的所有值都已经正确处理完毕, 才能结束 wgRespon := &sync.WaitGroup{}pearljam
// 启动读取结果的控制器
go func() {
// wgRespon计数器+1
wgRespon.Add(1)
// 读取结果
for respon := range responChannel {
// 处理结果
result = append(result, respon)
}
// 当 responChannel被关闭时且channel中所有的值都已经被处理完毕后, 将执⾏到这⼀⾏
wgRespon.Done()
}()
for _, url := range urls {
垃圾英文
// 计数器+1
wg.Add(1)
limiter <- true
// 这⾥在启动goroutine时, 将⽤来收集结果的局部变量channel也传递进去
go httpGet(url,responChannel, limiter, wg)
}
/
/ 等待所以协程执⾏完毕
wg.Wait() // 当计数器为0时, 不再阻塞
fmt.Println("所有协程已执⾏完毕")
// 关闭接收结果channel
clo(responChannel)
// 等待wgRespon的计数器归零
wgRespon.Wait()
// 返回聚合后结果
return result
}
func main() {
小学生英语自我介绍
urls := []int{1,2,3,4,5,6,7,8,9,10}
result := collect(urls)
fmt.Println(result)
}
接收多返回值
package main
import (
"fmt"
"sync"
)
func httpGet(url int,respon chan string,rep chan string, limiter chan bool, wg *sync.WaitGroup) { // 函数执⾏完毕时计数器-1
defer wg.Done()
// 将拿到的结果, 发送到参数中传递过来的channel中
respon <- fmt.Sprintf("http get: %d", url)
rep <- fmt.Sprintf("rep get: %d", url)
// 释放⼀个坑位
<- limiter
}
// 将所有的返回结果, 以 []string 的形式返回
func collect(urls []int) ([]string ,[]string){
var result []string
var tworesult []string
wg := &sync.WaitGroup{}
// 控制并发数为10
limiter := make(chan bool, 5)
defer clo(limiter)
// 函数内的局部变量channel, 专门⽤来接收函数内所有goroutine的结果
responChannel := make(chan string, 20)
repChannel := make(chan string, 20)
// 为读取结果控制器创建新的WaitGroup, 需要保证控制器内的所有值都已经正确处理完毕, 才能结束 wgRespon := &sync.WaitGroup{}
// 启动读取结果的控制器
// wgRespon计数器+2
wgRespon.Add(2)
go func() {
// 读取结果
for respon := range responChannel {
// 处理结果
result = append(result, respon)
}
// 当 responChannel被关闭时且channel中所有的值都已经被处理完毕后, 将执⾏到这⼀⾏
wgRespon.Done()
羸弱怎么读}()
go func() {
// 读取结果
for rep := range repChannel {
// 处理结果
tworesult = append(tworesult, rep)
}
// 当 responChannel被关闭时且channel中所有的值都已经被处理完毕后, 将执⾏到这⼀⾏
wgRespon.Done()
}()
for _, url := range urls {
// 计数器+1
wg.Add(1)
limiter <- true
/
/ 这⾥在启动goroutine时, 将⽤来收集结果的局部变量channel也传递进去
go httpGet(url,responChannel,repChannel, limiter, wg)
}
// 等待所以协程执⾏完毕
wg.Wait() // 当计数器为0时, 不再阻塞
fmt.Println("所有协程已执⾏完毕")
// 关闭接收结果channel
clo(responChannel)
clo(repChannel)
// 等待wgRespon的计数器归零
wgRespon.Wait()
/
/ 返回聚合后结果
return result,tworesult
}
func main() {
urls := []int{1,2,3,4,5,6,7,8,9,10}
result,tworesult := collect(urls)
fmt.Println(result)
fmt.Println(tworesult)
}