Skip to content

Instantly share code, notes, and snippets.

@cpusoft
Last active July 16, 2020 09:32
Show Gist options
  • Save cpusoft/35185fe7bbd66244af9d5fac57b5cd8f to your computer and use it in GitHub Desktop.
Save cpusoft/35185fe7bbd66244af9d5fac57b5cd8f to your computer and use it in GitHub Desktop.
得到协程的返回值
// go routine 返回值,main一般是不能获取的
// 需要通过channel,打通通道,得到返回值
package main
import (
"fmt"
"net/http"
)
// result封装错误,和其他需要附加的信息
type Result struct {
Error error
Response *http.Response
}
// 通过一个函数,将go封装起来,
// done 用于终止函数
// Result为返回值
func checkStatus(done <-chan interface{}, urls ...string) <-chan Result {
resultCh := make(chan Result)
go func() {
defer close(resultCh)
for _, url := range urls {
resp, err := http.Get(url)
result := Result{Error: err, Response: resp}
select {
case <-done:
return
case resultCh <- result:
}
}
}()
return resultCh
}
//如何返回go routine 的返回值
func main() {
done := make(chan interface{})
defer close(done)
urls := []string{"http://www.baidu.com/", "http://badhost/"}
for result := range checkStatus(done, urls...) {
if result.Error != nil {
fmt.Printf("error: %v", result.Error)
continue
}
fmt.Printf("Resonse :%v\n", result.Response.Status)
}
}
https://docs.lvrui.io/2020/03/26/go%E8%AF%AD%E8%A8%80%E5%9C%A8goroutine%E4%B8%AD%E6%8B%BF%E5%88%B0%E8%BF%94%E5%9B%9E%E5%80%BC/
有两种方法:
1 发送给独立的goroutine处理程序
package main
import (
"fmt"
"sync"
"time"
)
var responseChannel = make(chan string, 15)
func httpGet(url int, limiter chan bool, wg *sync.WaitGroup) {
// 函数执行完毕时 计数器-1
defer wg.Done()
fmt.Println("http get:", url)
responseChannel <- fmt.Sprintf("Hello Go %d", url)
// 释放一个坑位
<- limiter
}
func ResponseController() {
for rc := range responseChannel {
fmt.Println("response: ", rc)
}
}
func main() {
// 启动接收response的控制器
go ResponseController()
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("所有协程已执行完毕")
}
2 在当前函数中聚合返回
package main
import (
"fmt"
"sync"
)
func httpGet(url int,response chan string, limiter chan bool, wg *sync.WaitGroup) {
// 函数执行完毕时 计数器-1
defer wg.Done()
// 将拿到的结果, 发送到参数中传递过来的channel中
response <- fmt.Sprintf("http get: %d", url)
// 释放一个坑位
<- limiter
}
// 将所有的返回结果, 以 []string 的形式返回
func collect(urls []int) []string {
var result []string
wg := &sync.WaitGroup{}
// 控制并发数为10
limiter := make(chan bool, 5)
defer close(limiter)
// 函数内的局部变量channel, 专门用来接收函数内所有goroutine的结果
responseChannel := make(chan string, 20)
// 为读取结果控制器创建新的WaitGroup, 需要保证控制器内的所有值都已经正确处理完毕, 才能结束
wgResponse := &sync.WaitGroup{}
// 启动读取结果的控制器
go func() {
// wgResponse计数器+1
wgResponse.Add(1)
// 读取结果
for response := range responseChannel {
// 处理结果
result = append(result, response)
}
// 当 responseChannel被关闭时且channel中所有的值都已经被处理完毕后, 将执行到这一行
wgResponse.Done()
}()
for _, url := range urls {
// 计数器+1
wg.Add(1)
limiter <- true
// 这里在启动goroutine时, 将用来收集结果的局部变量channel也传递进去
go httpGet(url,responseChannel, limiter, wg)
}
// 等待所以协程执行完毕
wg.Wait() // 当计数器为0时, 不再阻塞
fmt.Println("所有协程已执行完毕")
// 关闭接收结果channel
close(responseChannel)
// 等待wgResponse的计数器归零
wgResponse.Wait()
// 返回聚合后结果
return result
}
func main() {
urls := []int{1,2,3,4,5,6,7,8,9,10}
result := collect(urls)
fmt.Println(result)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment