0

0

golang并发请求接口

WBOY

WBOY

发布时间:2023-05-10 11:58:06

|

1181人浏览过

|

来源于php中文网

原创

go语言是一种非常适合并发编程的编程语言,在实现高并发的服务或应用时,它的效能得到了很好的发挥。在日常开发中,我们可能会遇到需要并发请求接口或者并发处理大量的数据的场景,本文将介绍golang中如何实现并发请求接口。

并发请求接口的场景

在实际开发中,我们可能会遇到需要请求某个接口并获取响应数据的场景,比如:

  • 获取某个网站上的商品数据。
  • 从不同的API接口获取数据并汇总呈现。
  • 同时请求多个数据源以便快速收集数据。

在单线程中,如果需要请求多个接口,那么需要一个接口请求完成之后再去请求另一个接口,这会导致整个流程变得缓慢。相反,使用并发请求接口则可以同时发起多个请求,大大提高请求效率。

goroutine并发处理

goroutine是go语言中的一种特殊的函数,它可以在与主线程并行的特殊线程中运行。多个goroutine同时运行可以同时请求多个接口,请求完成之后再进行数据整合处理。并发使用goroutine比较容易实现,通过go关键字实现即可。

WaitGroup控制goroutine

在实际开发中,我们可能会发现可能有一些协程可能比较耗时,可能需要更多的时间才能返回结果。在这种情况下,我们需要等待协程返回结果,进行后面的处理。这时候,我们需要使用sync.WaitGroup来控制goroutine数量,确保所有请求都得到响应结果。

立即学习go语言免费学习笔记(深入)”;

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "sync"
)

var wg sync.WaitGroup // 声明一个sync.WaitGroup实例,用于协程控制

func main() {
    urls := []string{"https://www.baidu.com", "https://www.qq.com", "https://www.taobao.com", "https://www.jd.com", "https://www.mi.com"}

    // 通过遍历urls,启动goroutine
    for _, url := range urls {
        wg.Add(1) // 添加一个goroutine
        go getBody(url)
    }

    wg.Wait() // 等待所有goroutine结束
}

// getBody用于获取传入url的响应结果,并打印。
func getBody(url string) {
    resp, err := http.Get(url) // 发起http GET请求
    if err != nil {
        fmt.Println(err)
        return
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Printf("url: %s, contents:
%s
", url, string(body))
    wg.Done() // 相当于wg.Add(-1),标志该goroutine已经结束
}

在上面的代码中,我们先声明了一个sync.WaitGroup实例,用于协程数量控制。然后,在main()函数中,通过遍历urls启动了多个协程,同时每次启动协程时,都会调用wg.Add(1)方法,表示需要等待一个协程完成。这样的话,WaitGroup中记录的等待的协程数量就会变成urls中url数量。然后在go getBody(url)这一行,我们启动了请求url的协程,然后在协程结束的时候调用了wg.Done()方法,表示该协程已经结束。

最后,wg.Wait()调用使主协程等待所有协程结束。

并发请求的最佳实践

在实际开发中,我们需要注意一些细节,这些细节可以帮助我们更好地使用并发请求接口。

一、并发数量的控制

在并发请求接口的时候,我们需要控制并发的数量,特别是当接口请求数量比较大时,避免一次性请求使服务器受到太大压力。我们可以设立一个最大值,这样可以保证并发的最高数量。我们可以使用golang中的缓冲通道实现最大并发数的控制。

ch := make(chan struct{}, 5) // 声明一个缓冲通道,大小为5,控制并发数量为5

for _, url := range urls {
    ch <- struct{}{} // 把协程数量放在通道里
    wg.Add(1)  // 添加一个goroutine
    go func(url string) {
        defer wg.Done()
        getBody(url)
        <-ch // 从通道里取出一个值,表示这个协程已经结束
    }(url)
}

在声明缓冲通道的过程中,我们设置缓冲大小为5,表示最多同时运行5个goroutine,接着我们遍历urls,向通道中加入结构体值。

Nanonets
Nanonets

基于AI的自学习OCR文档处理,自动捕获文档数据

下载

在启动goroutine的时候,我们声明了一个func(url string)为处理函数,避免同时运行goroutine的最大数量超过5个,然后调用getBody(url)方法。在goroutine结束的时候,我们通过通道释放一个信号,表示有一个goroutine结束了——<-ch

二、避免请求阻塞

在进行并发请求接口的时候,我们需要避免请求阻塞,通常出现在在一个请求长时间没有相应时。我们可以使用Golang中的context.Context解决这个问题。如果请求超时,则取消阻塞的请求。

url := "https://httpstat.us/200?sleep=8000"

ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*5000) // 告诉请求,5秒之后自动取消

defer cancel()

req, err := http.NewRequestWithContext(ctx, "GET", url, nil) // 使用请求上下文

if err != nil {
    log.Fatal(err)
}

client := http.DefaultClient
resp, err := client.Do(req) // 发起请求
if err != nil {
    log.Fatal(err)
}

if resp.StatusCode == http.StatusOK {
    contents, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s
", contents)
}

在上面的代码中,我们使用了context.WithTimeout方法创建了一个请求上下文,其timeout设置为5秒,例如http://httpstat.us/200?sleep=8000,这个请求需要8秒才能返回数据。然后我们使用http.NewRequestWithContext方法创建一个使用请求上下文的请求。在发送请求时,我们使用http.DefaultClient发起请求。最后,如果响应状态码是200,则输出响应数据。

当请求超时时,请求链路就会被直接关掉。这时我们会受到“context deadline exceeded”错误的提示。

三、避免请求重复

在请求接口时,可能会遇到重复请求同一个接口的情况,在这种情况下,我们应该避免重复请求同一个接口,这会浪费宝贵的时间和资源。我们可以使用Golang中的sync.Map解决这个问题。

var m = sync.Map{}

url := "https://httpbin.org/get"

wg.Add(2)
go doGet(url, &m, &wg)
go doGet(url, &m, &wg)

wg.Wait()

func doGet(url string, m *sync.Map, wg *sync.WaitGroup) {
    _, loaded := m.LoadOrStore(url, true) // 表示url已经被请求过,如果已存在,则直接返回,否则返回false并储存

    if loaded {
        fmt.Printf("url %s already requested.
", url)
        wg.Done()
        return
    }

    resp, err := http.Get(url)
    if err != nil {
        log.Fatal(err)
    }

    defer resp.Body.Close()
    contents, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s
", contents)
    wg.Done()
}

在上面的代码中,我们使用了一个sync.Map来保证url只被请求一次。在doGet协程中,我们使用m.LoadOrStore(url, true)来判断url是否已经被请求过,如果请求过了,就return直接退出协程。否则,我们发起http.Get请求并在log中打印响应数据。最后,我们通过wg.Done()方法标志协程已经结束。

总结

本文介绍了使用golang实现并发请求接口的方法。通过使用goroutine并发处理,WaitGroup协程控制,以及缓冲通道控制并发数量。通过在请求上下文中设置超时来避免请求阻塞,并且使用sync.Map避免请求重复。通过使用这些技术,我们可以大大提高请求接口的效率,提升编码效率和编程体验。

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
golang如何定义变量
golang如何定义变量

golang定义变量的方法:1、声明变量并赋予初始值“var age int =值”;2、声明变量但不赋初始值“var age int”;3、使用短变量声明“age :=值”等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

211

2024.02.23

golang有哪些数据转换方法
golang有哪些数据转换方法

golang数据转换方法:1、类型转换操作符;2、类型断言;3、字符串和数字之间的转换;4、JSON序列化和反序列化;5、使用标准库进行数据转换;6、使用第三方库进行数据转换;7、自定义数据转换函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

247

2024.02.23

golang常用库有哪些
golang常用库有哪些

golang常用库有:1、标准库;2、字符串处理库;3、网络库;4、加密库;5、压缩库;6、xml和json解析库;7、日期和时间库;8、数据库操作库;9、文件操作库;10、图像处理库。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

356

2024.02.23

golang和python的区别是什么
golang和python的区别是什么

golang和python的区别是:1、golang是一种编译型语言,而python是一种解释型语言;2、golang天生支持并发编程,而python对并发与并行的支持相对较弱等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

214

2024.03.05

golang是免费的吗
golang是免费的吗

golang是免费的。golang是google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的开源编程语言,采用bsd开源协议。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

409

2024.05.21

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

490

2025.06.09

golang相关判断方法
golang相关判断方法

本专题整合了golang相关判断方法,想了解更详细的相关内容,请阅读下面的文章。

201

2025.06.10

golang数组使用方法
golang数组使用方法

本专题整合了golang数组用法,想了解更多的相关内容,请阅读专题下面的文章。

1478

2025.06.17

Python异步编程与Asyncio高并发应用实践
Python异步编程与Asyncio高并发应用实践

本专题围绕 Python 异步编程模型展开,深入讲解 Asyncio 框架的核心原理与应用实践。内容包括事件循环机制、协程任务调度、异步 IO 处理以及并发任务管理策略。通过构建高并发网络请求与异步数据处理案例,帮助开发者掌握 Python 在高并发场景中的高效开发方法,并提升系统资源利用率与整体运行性能。

37

2026.03.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号