在 Golang 中使用 Go 关键字和 Channel 实现并行

前端之家收集整理的这篇文章主要介绍了在 Golang 中使用 Go 关键字和 Channel 实现并行前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

Go 关键字和 channel 的用法

go 关键字用来创建 goroutine (协程),是实现并发的关键。go 关键字的用法如下:
  1. //go 关键字放在方法调用前新建一个 goroutine 并让他执行方法
  2. go GetThingDone(param1,param2);
  3.  
  4. //上例的变种,新建一个匿名方法并执行
  5. go func(param1,param2) {
  6. }(val1,val2)
  7.  
  8. //直接新建一个 goroutine 并在 goroutine 中执行代码
  9. go {
  10. //do someting...
  11. }
因为 goroutine 在多核 cpu 环境下是并行的。如果代码块在多个 goroutine 中执行,我们就实现了代码并行。那么问题来了,怎么拿到并行的结果呢?这就得用 channel 了。
  1. //resultChan 是一个 int 类型的 channel。类似一个信封,里面放的是 int 类型的值。
  2. var resultChan chan int
  3. //将 123 放到这个信封里面,供别人从信封中取用
  4. resultChan <- 123
  5. //从 resultChan 中取值。这个时候 result := 123
  6. result := <- resultChan

使用 go 关键字和 channel 实现非阻塞调用

阻塞的意思是调用方在被调用代码返回之前必须一直等待,不能处理别的事情。而非阻塞调用则不用等待,调用之后立刻返回。那么返回值如何获取呢?Node.js 使用的是回调的方式,Golang 使用的是 channel。
  1. /**
  2. * 每次调用方法会新建一个 channel : resultChan,
  3. * 同时新建一个 goroutine 来发起 http 请求并获取结果。
  4. * 获取到结果之后 goroutine 会将结果写入到 resultChan。
  5. */
  6. func UnblockGet(requestUrl string) chan string {
  7. resultChan := make(chan string)
  8. go func() {
  9. request := httplib.Get(requestUrl)
  10. content,err := request.String()
  11. if err != nil {
  12. content = "" + err.Error()
  13. }
  14. resultChan <- content
  15. } ()
  16. return resultChan
  17. }

由于新建的 goroutine 不会阻塞函数主流程的执行,所以调用 UnblockGet 方法会立刻得到一个 resultChan 返回值。一旦 goroutine 执行完毕拿到结果就会写入到 resultChan 中,这时外部就可以从 resultChan 中获取执行结果。

一个很 low 的并行示例

  1. fmt.Println(time.Now())
  2. resultChan1 := UnblockGet("http://127.0.0.1/test.PHP?i=1")
  3. resultChan2 := UnblockGet("http://127.0.0.1/test.PHP?i=2")
  4.  
  5. fmt.Println(<-resultChan1)
  6. fmt.Println(<-resultChan1)
  7. fmt.Println(time.Now())

上面两个 http 请求是在两个 goroutine 中并行的。总的执行时间小于 两个请求时间和。

这个例子只是为了体现 go 和 channel 的用法,有内存泄漏问题,千万不要在线上这么搞。因为新建的 channel 没有 close。下次写一个更高级一点的。

简单的实现 http multi GET

  1. type RemoteResult struct {
  2. Url string
  3. Result string
  4. }
  5.  
  6. func RemoteGet(requestUrl string,resultChan chan RemoteResult) {
  7. request := httplib.NewBeegoRequest(requestUrl,"GET")
  8. request.SetTimeout(2 * time.Second,5 * time.Second)
  9. //request.String()
  10. content,err := request.String()
  11. if err != nil {
  12. content = "" + err.Error()
  13. }
  14. resultChan <- RemoteResult{Url:requestUrl,Result:content}
  15. }
  16. func MultiGet(urls []string) []RemoteResult {
  17. fmt.Println(time.Now())
  18. resultChan := make(chan RemoteResult,len(urls))
  19. defer close(resultChan)
  20. var result []RemoteResult
  21. //fmt.Println(result)
  22. for _,url := range urls {
  23. go RemoteGet(url,resultChan)
  24. }
  25. for i:= 0; i < len(urls); i++ {
  26. res := <-resultChan
  27. result = append(result,res)
  28. }
  29. fmt.Println(time.Now())
  30. return result
  31. }
  32.  
  33. func main() {
  34. urls := []string{
  35. "http://127.0.0.1/test.PHP?i=13","http://127.0.0.1/test.PHP?i=14","http://127.0.0.1/test.PHP?i=15","http://127.0.0.1/test.PHP?i=16","http://127.0.0.1/test.PHP?i=17","http://127.0.0.1/test.PHP?i=18","http://127.0.0.1/test.PHP?i=19","http://127.0.0.1/test.PHP?i=20" }
  36. content := MultiGet(urls)
  37. fmt.Println(content)
  38. }

猜你在找的Go相关文章