Go并发控制WaitGroup的使用场景分析

Go并发控制WaitGroup的使用场景分析

Go语言的并发模型是通过goroutine和channel实现的。goroutine是轻量级线程,可以在同一进程的多个线程之间切换执行。channel提供了goroutine之间的通信和同步机制。在使用goroutine时,我们很常用到sync.WaitGroup来控制并发。本文将详细讲解WaitGroup的使用场景和用法。

WaitGroup的基本用法

在Go语言中,sync.WaitGroup是一个计数器,它可以用来等待多个goroutine执行完毕。WaitGroup内部有一个计数器,最初为0,可以通过sync.WaitGroup的方法Add来设置要等待的goroutine的个数,每个goroutine在执行完后调用Done方法通知WaitGroup,计数器会减1。当计数器清零后,所有的等待在Wait方法上的goroutine都会被唤醒执行。

例如,我们有3个任务需要并发执行,每个任务执行时间不同,代码如下:

package main

import (
    "fmt"
    "sync"
    "time"
)

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done()
    fmt.Printf("Worker %d starting\n", id)
    time.Sleep(time.Second)
    fmt.Printf("Worker %d done\n", id)
}

func main() {
    var wg sync.WaitGroup
    for i := 1; i <= 3; i++ {
        wg.Add(1)
        go worker(i, &wg)
    }
    wg.Wait()
    fmt.Println("All workers done.")
}

程序的核心是worker函数,每个worker函数作为一个goroutine并发执行。在main函数中,我们先创建了一个WaitGroup实例,然后使用wg.Add(1)增加了3次计数器,然后启动3个goroutine并传入WaitGroup,每个worker函数执行完毕后调用wg.Done()通知WaitGroup计数器减1。当计数器清零后,执行wg.Wait()的goroutine(本例即main函数)会被唤醒执行。

输出结果:

Worker 1 starting
Worker 2 starting
Worker 3 starting
Worker 3 done
Worker 1 done
Worker 2 done
All workers done.

WaitGroup的高级用法

并发请求数据

另外一个常用场景是并发请求数据。比如我们要从多个API接口中同时请求数据,然后汇总结果。

package main

import (
    "fmt"
    "sync"
    "time"
)

// 模拟API接口
func api(i int) int {
    time.Sleep(time.Second)
    return i * 2
}

func fetch(id int, wg *sync.WaitGroup, result chan int) {
    defer wg.Done()
    r := api(id)
    result <- r
}

func main() {
    var wg sync.WaitGroup
    result := make(chan int, 3)

    for i := 1; i <= 3; i++ {
        wg.Add(1)
        go fetch(i, &wg, result)
    }

    wg.Wait()
    close(result)

    sum := 0
    for r := range result {
        sum += r
    }
    fmt.Println("Total:", sum)
}

在本例中,我们模拟了一个API请求,每个请求需要1秒的处理时间。fetch函数作为goroutine并发调用api函数获取数据。当api请求完成后,fetch会将结果写入result channel中。main函数等待所有的fetch goroutine执行完毕后,关闭channel。最后,从channel中读取所有的结果并计算总和。

输出结果:

Total: 12

并发请求大量数据

另一个常见的场景是并发请求大量数据。在本场景中,我们会启动若干个goroutine并发请求数据,并将每个goroutine的结果计算起来。由于数据量非常大,无法一次性处理完毕,因此需要把数据按照一定的范围分成多个部分进行处理,并把多个部分的结果合并起来。

package main

import (
    "fmt"
    "sync"
)

const (
    dataSize  = 1000000
    goroutine = 100
)

// 模拟获取数据
func getData(start, end int) []int {
    data := make([]int, end-start)
    for i := 0; i < end-start; i++ {
        data[i] = start + i
    }
    return data
}

// 计算结果
func sum(data []int, result chan int, wg *sync.WaitGroup) {
    s := 0
    for _, v := range data {
        s += v
    }
    result <- s
    wg.Done()
}

func main() {
    var wg sync.WaitGroup
    result := make(chan int, goroutine)

    for i := 0; i < goroutine; i++ {
        wg.Add(1)
        start := i * (dataSize / goroutine)
        end := (i + 1) * (dataSize / goroutine)
        data := getData(start, end)
        go sum(data, result, &wg)
    }

    wg.Wait()
    close(result)

    sum := 0
    for r := range result {
        sum += r
    }
    fmt.Println("Total:", sum)
}

在本例中,我们模拟了一个包含100万个数据的序列。我们将这个序列分成100个部分,每个部分10000个数据。然后,我们使用100个goroutine并发地计算每个部分的数据,并将结果写入result channel。main函数会等待所有goroutine执行完毕后,关闭channel并计算所有结果的总和。

输出结果:

Total: 499999500000

总结

本文介绍了sync.WaitGroup的基本使用方法和高级使用方法。在实际开发中,WaitGroup可以帮助我们控制并发执行的goroutine,通过等待所有goroutine执行完毕后再执行后续操作,可以避免程序运行出现不可预期的结果。在实际使用中,需要根据具体的需求选择合适的方式和参数设置,并注意避免死锁等问题。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Go并发控制WaitGroup的使用场景分析 - Python技术站

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

相关文章

  • Kotlin server多线程编程详细讲解

    Kotlin server多线程编程详细讲解 在Kotlin中,使用多线程编程非常方便。下面将详细介绍多线程编程的使用方法和一些示例。 线程池的概念和使用 线程池是一种用于控制线程数量和复用线程的机制。使用线程池可以减少线程创建和销毁的开销,提高程序执行效率。在Kotlin中,我们可以使用java.util.concurrent中的线程池相关类来实现线程池的…

    多线程 2023年5月17日
    00
  • Python2.7实现多进程下开发多线程示例

    Python2.7实现多进程下开发多线程示例的完整攻略如下: 1.多进程下开发多线程的原理 在Python中,多线程本质上还是单线程,因为CPython解释器存在GIL(全局锁)机制,但是多线程可以充分利用多核CPU的性能。而多进程则是真正的并行,但是相比多线程会更加消耗系统资源,因此在实际应用中需要根据具体情况进行选择。 多进程下开发多线程,其原理是在每个…

    多线程 2023年5月17日
    00
  • Java多线程之Future设计模式

    下面是详细的讲解“Java多线程之Future设计模式”的完整攻略。 什么是Future设计模式 Future设计模式是一种Java多线程技术,它可以在一个线程中异步执行某些任务,然后在未来的某个时间点获取任务的结果。通常情况下,我们会使用Future设计模式来加快应用程序的响应速度,因为它可以将应用程序的某些任务异步化,使得这些任务的执行速度不会影响其他任…

    多线程 2023年5月16日
    00
  • Java CompletableFuture实现多线程异步编排

    Java CompletableFuture是Java提供的一种基于Future实现的异步编程方式。它可以在执行异步任务的同时,继续执行其他的任务,并且当异步任务完成时,它可以自动回调指定的函数,从而实现了多线程的异步编排。 下面给出Java CompletableFuture实现异步编排的攻略: 1. 创建CompletableFuture对象 Java …

    多线程 2023年5月17日
    00
  • collection集合体系与并发修改异常的解决方法

    下面我来详细讲解“collection集合体系与并发修改异常的解决方法”。 一、collection集合体系介绍 Java的集合体系分为List、Set、Map三种,它们分别对应了序列、集合和映射这三个数学概念。 List是有序的,更像是一个数组,但它不存在固定长度的限制,可以动态增加删除,比数组更灵活方便。List常用的实现类包括ArrayList、Lin…

    多线程 2023年5月16日
    00
  • Java并发系列之AbstractQueuedSynchronizer源码分析(共享模式)

    我会给出完整的攻略。 Java并发系列之AbstractQueuedSynchronizer源码分析(共享模式) 前言 AbstractQueuedSynchronizer 是 Java 并发工具包中的一个重要组件,它提供了同步机制的底层实现,常被用于自定义同步器、锁以及其他相关工具的实现。其中,共享模式是 AQS 最为核心的实现之一。 AQS 共享锁机制 …

    多线程 2023年5月16日
    00
  • Java并发编程之Executors类详解

    Java并发编程之Executors类详解 前言 在Java并发编程中,Executor Framework是一个非常重要的工具,可以帮助我们完成任务的管理、创建、调度和执行。Executors类是Executor Framework中的一个核心类,主要用于创建不同类型的Executor。 在本篇攻略中,我们将详细讲解Executors类的使用方法和相关注意…

    多线程 2023年5月17日
    00
  • python单线程下实现多个socket并发过程详解

    本文将为大家详细讲解如何在 Python 单线程下实现多个 socket 并发,具体内容如下: 1. 什么是 socket socket 是计算机上的一个抽象概念,就像打电话需要电话机一样,在网络中发送信息需要由 socket 传递和接收。在 Python 编程语言中,socket 是标准库中用于实现网络通信的一种方式。 2. 单线程下实现多个 socket…

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