详解Golang 中的并发限制与超时控制

详解Golang 中的并发限制与超时控制

前言

该文主要讲述在 Golang 中如何控制并发数以及如何实现请求的超时控制。在实际的开发中,这两个问题是非常重要的,同时在一些性能优化场景下也会起到很大的作用。

控制并发

在 Golang 中,我们可以通过设置goroutine的数量来控制并发的数量。假设我们有一个需求,在获取照片的时候我们不希望并发数量过高,同时也不希望请求照片的过程中出现错误。我们此时可以通过使用一个带有限制并发量的队列来实现这个功能。

基本思路

我们可以先定义一个函数来获取照片,假设这个函数是 getPicture,然后我们创建一个带有固定缓存大小的 Channel,将需要获取照片的任务放进去。我们可以定义一个goroutine,并从 Channel 中取出任务。对于每个任务,我们可以将此任务的处理放入到另外一个带有一个goroutine的 Channel 中,并阻塞,等待网上获取照片,同时会使用一个计数器来记录处理的任务的数量。每当处理完一个任务时,该计数器的值会自增,最终在该 Channel 中收到所有的响应之后,我们可以将所有任务的响应放入到一个结果数组中。

示例代码

下面是一个带有并发限制的获取照片的示例代码,只会同时进行2个任务的处理。

package main

import (
    "fmt"
    "time"
)

func main() {
    start := time.Now()
    // 声明并发限制为 2 的缓存型通道
    c := make(chan int, 2)
    var urls = []string{"http://www.baidu.com", "http://www.sina.com", "http://www.sohu.com", "http://www.qq.com", "http://www.taobao.com", "http://www.tmall.com", "http://www.jd.com", "http://www.163.com"}
    responses := []string{}

    // 开始处理任务
    for _, url := range urls {
        // 将任务放到 Channel 中,并开启 goroutine 进行处理
        c <- 1
        go func(url string) {
            // 处理任务
            response := fmt.Sprintf("Url: %s, Result: XXX", url)
            responses = append(responses, response)

            // 执行完任务后,从 Channel 中取出标记
            <-c
        }(url)
    }

    // 等待任务完成
    for {
        if len(c) == 0 {
            break
        }
    }

    // 处理所有任务响应,仅为示例,执行一个简单的输出
    for _, response := range responses {
        fmt.Println(response)
    }

    fmt.Printf("Elapsed time: %s", time.Since(start))
}

超时控制

在 Golang 中,我们也可以通过一个 context 变量和 time 包配合来实现请求超时的控制。下面我们将通过一个示例来讲解如何实现该功能。

基本思路

我们假设我们要请求一个 API 以获取数据,但是由于网络可能出现问题或 API 服务不可用等情况,我们不能保证所有请求都能及时得到响应。另外,我们也不希望等待所有请求都超时后才能返回结果。因此,我们可以使用上下文和超时作为 API 请求的两个主要参数。我们可以使用context 模块来控制请求的生命周期,而 time.AfterFunc() 可以用于设置超时定时器,一旦定时器被触发时,将会导致 API 请求取消。

示例代码

下面是一个带有超时控制的 API 请求示例。

package main

import (
    "context"
    "fmt"
    "net/http"
    "time"
)

func main() {
    // 创建上下文
    ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
    defer cancel()

    tr := &http.Transport{}
    client := &http.Client{Transport: tr}

    // 发送请求
    req, _ := http.NewRequest("GET", "http://httpbin.org/get", nil)
    req = req.WithContext(ctx)

    // 设置超时定时器
    ch := make(chan int, 1)
    go func() {
        time.Sleep(3 * time.Second)
        ch <- 1
    }()

    // 等待 API 请求响应
    select {
    case <-ch:
        fmt.Println("API请求超时")
    case <-ctx.Done():
        fmt.Println("API请求取消")
        return
    default:
        res, err := client.Do(req)
        if err != nil {
            fmt.Println(err.Error())
            return
        }

        defer res.Body.Close()

        fmt.Println("API请求成功")
    }
}

在上面的示例中,我们首先创建一个上下文变量,然后使用一个 http.Client 对象初始化一个 GET 请求。接着我们创建一个带有指定超时时间的 Channel,并使用定时器开启一个子线程等待超时时间到达。最后,我们在一个 select 语句中等待 API 请求响应返回,一旦定时器到期,我们将会收到一个来自超时定时器的响应,根据响应来取消 API 请求。

结尾

本篇文章主要讲解了 Golang 中如何控制并发以及如何实现请求的超时控制。这些方案都是非常重要的,可以帮助我们更好地定制化和优化在大型系统中的性能。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解Golang 中的并发限制与超时控制 - Python技术站

(0)
上一篇 2023年5月16日
下一篇 2023年5月16日

相关文章

  • Java并发编程之死锁相关知识整理

    Java并发编程之死锁相关知识整理 什么是死锁? 死锁是指两个或多个线程在执行过程中,因互相竞争资源而造成的一种互相等待的现象,若无外力干涉势将无法推进下去。 什么情况下会发生死锁? 当系统资源不足时,进程会因争夺资源而陷入僵局。若此时系统能够协调资源分配,以便令进程有序地进行,便可避免进程间死锁的发生。 在Java并发编程中,一般出现死锁的情况是因为线程之…

    多线程 2023年5月16日
    00
  • C++线程之thread详解

    C++线程之thread详解 简介 线程是现代程序设计中最重要和有用的概念之一,是使程序在同时执行多个任务的机制。C++语言提供了标准库中的thread类,使得在C++中创建线程非常简单。本文将对thread的用法进行详细的讲解和说明,包括如何创建和管理线程、如何进行线程同步等内容。 创建线程 C++线程库提供了std::thread类用于创建和管理线程。创…

    多线程 2023年5月17日
    00
  • java并发编程专题(五)—-详解(JUC)ReentrantLock

    Java并发编程专题(五)——详解(JUC)ReentrantLock ReentrantLock是java.util.concurrent(J.U.C)包中的一个锁工具类,也是Java多线程中常用的互斥锁。它可用于代替synchronized关键字进行线程同步,比synchronized更灵活。 1. 使用ReentrantLock 1.1 创建Reent…

    多线程 2023年5月16日
    00
  • Java多线程之如何确定线程数的方法

    下面我会详细讲解如何确定Java多线程中线程数的方法。 一、为什么需要确定线程数 在使用Java多线程的过程中,我们需要考虑如何合理地设置线程数。过多的线程数会导致线程频繁切换,资源浪费,过少的线程数则会导致程序执行效率低下,容易发生阻塞等问题。因此,为了充分利用计算机的处理能力,我们需要根据实际情况合理地设置线程数。 二、确定线程数的方法 下面介绍几种常用…

    多线程 2023年5月16日
    00
  • Java 高并发十: JDK8对并发的新支持详解

    Java 高并发十: JDK8对并发的新支持详解 简介 JDK8中加入了许多新特性,对Java语言的并发编程提供了更好的支持。本文将对JDK8中新增的并发编程特性进行详细介绍。 1. CompletableFuture CompletableFuture是JDK8中新增的一个异步编程工具类,能够方便地处理多个并发任务的结果。它的主要特点包括以下几点: 支持流…

    多线程 2023年5月16日
    00
  • C/C++中线程基本概念与创建详解

    C/C++中线程基本概念与创建详解 什么是线程? 线程是进程中的一个执行单元,一个进程可以有多个线程,各个线程可以并行执行不同的任务,彼此之间相对独立。线程共享进程的地址空间,可以方便地相互通信。 线程的创建 在C/C++语言中,可以通过调用系统提供的API函数来创建线程。常见的API函数有: CreateThread():Windows系统下的线程创建AP…

    多线程 2023年5月17日
    00
  • PHP安装threads多线程扩展基础教程

    标题:PHP安装threads多线程扩展基础教程 1. 确认服务器环境 在安装threads多线程扩展前,需先确认一下服务器环境是否满足以下要求: PHP版本:5.5以上 SAPI类型:CLI(Command Line Interface) 系统:Linux/Unix/MacOS 2. 安装pthreads多线程扩展 2.1 下载pthreads扩展 git…

    多线程 2023年5月16日
    00
  • java并发之synchronized

    Java 并发之 synchronized 在 Java 中,我们可以使用 synchronized 来保证多线程程序的线程安全。本文将介绍 synchronized 的使用方式和注意事项。 synchronized 使用方式 synchronized 有三种使用方式: 1. 修饰实例方法 public synchronized void method() …

    多线程 2023年5月16日
    00
合作推广
合作推广
分享本页
返回顶部