执行go协程时, 是没有返回值的, 这时候需要用到go语言中特色的channel来获取到返回值. 通过channel拿到返回值有两种处理形式, 一种形式是具有go风格特色的, 即发送给一个for channel
或select channel
的独立goroutine中, 由该独立的goroutine来处理函数的返回值. 还有一种传统的做法, 就是将所有goroutine的返回值都集中到当前函数, 然后统一返回给调用函数.
发送给独立的goroutine处理程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| package main
import ( "fmt" "sync" "time" )
var responseChannel = make(chan string, 15)
func httpGet(url int, limiter chan bool, wg *sync.WaitGroup) { 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() {
go ResponseController()
wg := &sync.WaitGroup{} limiter := make(chan bool, 20)
for i := 0; i < 99; i++ { wg.Add(1) limiter <- true go httpGet(i, limiter, wg) } wg.Wait() fmt.Println("所有协程已执行完毕") }
|
这种具有Go语言特色的处理方式的关键在于, 你需要预先创建一个用于处理返回值的公共管道. 然后定义一个一直在读取该管道的函数, 该函数需要预先以单独的goroutine形式启动.
最后当执行到并发任务时, 每个并发任务得到结果后, 都会将结果通过管道传递到之前预先启动的goroutine中.
在当前函数中聚合返回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| package main
import ( "fmt" "sync" )
func httpGet(url int,response chan string, limiter chan bool, wg *sync.WaitGroup) { defer wg.Done() response <- fmt.Sprintf("http get: %d", url) <- limiter }
func collect(urls []int) []string { var result []string
wg := &sync.WaitGroup{} limiter := make(chan bool, 5) defer close(limiter)
responseChannel := make(chan string, 20) wgResponse := &sync.WaitGroup{} go func() { wgResponse.Add(1) for response := range responseChannel { result = append(result, response) } wgResponse.Done() }()
for _, url := range urls { wg.Add(1) limiter <- true go httpGet(url,responseChannel, limiter, wg) }
wg.Wait() fmt.Println("所有协程已执行完毕")
close(responseChannel)
wgResponse.Wait() return result }
func main() { urls := []int{1,2,3,4,5,6,7,8,9,10}
result := collect(urls) fmt.Println(result) }
|