使用golangwaitgroup实现并发任务

一、什么是golangwaitgroup

golangwaitgroup是Go语言中的一个并发原语,它能够有效地控制执行goroutine的顺序。它类似于一个计数器,可以在启动一组goroutine之前,将计数器设置为指定的值,然后将计数器逐个减1,直到计数器值为0,它会等待所有并发任务完成之后再进行下一步的操作。

为了使用golangwaitgroup,我们需要先导入“sync”包,然后实例化一个wait group,通过wait group的方法(Add、Done、Wait)来控制并发任务的执行顺序。

二、如何使用golangwaitgroup编写并发任务

下面是一个简单的例子,演示如何使用golangwaitgroup实现几个并发任务:

package main

import (
    "fmt"
    "sync"
)

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done()
    fmt.Printf("Worker %d starting\n", id)
    // 模拟耗时操作
    for i := 0; i < 100000000; i++ {

    }
    fmt.Printf("Worker %d done\n", id)
}

func main() {
    var wg sync.WaitGroup

    for i := 1; i <= 5; i++ {
        wg.Add(1)
        go worker(i, &wg)
    }

    wg.Wait()
    fmt.Println("All workers done!")
}

在这个例子中,我们定义了一个worker函数来代表具体的并发任务,worker函数接受一个id值和一个wait group作为参数,打印一些信息然后模拟一个耗时的操作。

在main函数中,我们实例化了一个wait group,然后启动了5个goroutine,每一个goroutine都调用worker函数,当一个goroutine结束时,调用wait group的Done()方法来减少计数器的值。

调用wait group的Wait()方法会阻塞当前goroutine之后的代码,直到所有的goroutine都完成并且计数器的值变为0。

三、如何解决golangwaitgroup的常见问题

使用golangwaitgroup如果没有正确处理可能会导致几个常见的问题,下面是一些通用的方法来解决这些问题。

并发调用时,如何避免重复调用

在并发调用时,我们需要确保多个goroutine不会同时调用同一个函数,否则可能会导致不可预期的结果。一个常见的解决方法就是通过channel来控制goroutine的并发数量,代码如下:

package main

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

func worker(id int, jobs <-chan int, results chan<- int, wg *sync.WaitGroup) {
    defer wg.Done()
    for j := range jobs {
        fmt.Printf("worker %d starting job %d\n", id, j)
        // 模拟耗时操作
        for i := 0; i < 100000000; i++ {

        }
        fmt.Printf("worker %d finished job %d\n", id, j)
        results <- j * 2
    }
}

func main() {
    var wg sync.WaitGroup

    numJobs := 10
    jobs := make(chan int, numJobs)
    results := make(chan int, numJobs)

    for w := 1; w <= 3; w++ {
        wg.Add(1)
        go worker(w, jobs, results, &wg)
    }

    for j := 1; j <= numJobs; j++ {
        jobs <- j
    }
    close(jobs)

    wg.Wait()
    close(results)

    for r := range results {
        fmt.Println(r)
    }
}

在这个例子中,我们创建了两个channel,一个用于存放任务,另一个用于存放结果。每一个goroutine都从jobs channel中读取任务,然后执行任务。如果jobs channel被关闭,那么goroutine就会退出。

使用channel来控制goroutine的并发数量也可以避免在调用Wait()方法时出现死锁的情况,因为我们已经在指定的goroutine数量处理完后关闭了jobs channel。

当任务出现错误时,如何正确定义wait group的计数

在工作过程中,有可能某些任务不会完成,比如说因为网络问题而出现连接失败等。在这种情况下,如果直接调用Done()方法,会导致计数器的值错误地递减,从而导致程序无法正确退出。

一个常见的解决方法就是在defer语句中捕获错误,然后在错误处理代码中将计数器的值增加回来,以保证计数器在出现错误后仍能够正确处理。

package main

import (
    "fmt"
    "sync"
)

func worker(id int, wg *sync.WaitGroup) {
    defer func() {
        if err := recover(); err != nil {
            fmt.Println("Worker failed:", err)
            wg.Add(1)
        }
        wg.Done()
    }()
    fmt.Printf("Worker %d starting\n", id)
    // 模拟出现错误的情况
    if id == 3 {
        panic("worker failed")
    }
    fmt.Printf("Worker %d done\n", id)
}

func main() {
    var wg sync.WaitGroup

    for i := 1; i <= 5; i++ {
        wg.Add(1)
        go worker(i, &wg)
    }

    wg.Wait()
    fmt.Println("All workers done!")
}

在这个例子中,我们在worker函数中模拟了一个出现错误的情况,当第三个goroutine执行的时候,会抛出一个panic异常,然后被main函数的defer语句捕获。

在defer语句中,我们首先检查是否有错误发生,如果有的话,就打印出来,然后调用wait group的Add()方法将计数器的值增加1。

在实际的工作中,我们也可以通过其他的方式来处理错误,比如说使用日志来记录错误信息,然后再根据错误之前的状态来恢复重试。

原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/182060.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝小蓝
上一篇 2024-11-24 06:18
下一篇 2024-11-24 06:18

相关推荐

  • Java任务下发回滚系统的设计与实现

    本文将介绍一个Java任务下发回滚系统的设计与实现。该系统可以用于执行复杂的任务,包括可回滚的任务,及时恢复任务失败前的状态。系统使用Java语言进行开发,可以支持多种类型的任务。…

    编程 2025-04-29
  • Saturn 定时任务用法介绍

    本文将从以下几个方面对Saturn定时任务进行详细的阐述: 一、Saturn 定时任务简介 Saturn是一个分布式任务调度系统,支持在线添加、修改定时任务,支持多种任务类型,如J…

    编程 2025-04-29
  • 如何在dolphinscheduler中运行chunjun任务实例

    本文将从多个方面对dolphinscheduler运行chunjun任务实例进行详细的阐述,包括准备工作、chunjun任务配置、运行结果等方面。 一、准备工作 在运行chunju…

    编程 2025-04-28
  • dotask——高效易用的任务执行框架

    一、任务执行框架介绍 在一个复杂的系统中,通常存在大量的任务需要执行。这些任务包括但不限于:发送邮件、处理数据、调用服务、生成报表等。在传统的编程模式中,我们往往需要手动编写任务调…

    编程 2025-04-25
  • 深入浅出runafter——异步任务调度器的实现

    一、runafter是什么? runafter是一个基于JavaScript实现的异步任务调度器,可以帮助开发人员高效地管理异步任务。利用runafter,开发人员可以轻松地定义和…

    编程 2025-04-23
  • 任务型对话系统

    一、什么是任务型对话系统 任务型对话系统是一种人工智能技术,旨在提供一种自然的方式,帮助用户完成特定的任务,例如预定机票、预定餐厅等。与传统的基于规则的对话系统不同,任务型对话系统…

    编程 2025-04-23
  • Java DelayQueue:实现延迟任务的线程安全队列

    一、DelayQueue的概述 Java的DelayQueue 是一个阻塞队列队列,主要用来实现对延迟任务的调度,也就是在指定的时间之后才能够取出任务来执行。该队列中保存的元素都必…

    编程 2025-04-23
  • 详解计划任务服务

    一、计划任务服务简介 计划任务服务是Windows操作系统提供的一种服务,可以定时执行指定的任务程序或命令行,如定时备份数据、更新软件、清理临时文件等。计划任务服务提供了一种自动化…

    编程 2025-04-23
  • Mac定时任务:实现自动化操作

    在现代社会,为了省时省力,我们越来越依赖计算机自动化操作。Mac作为一款非常普及的电脑系统,也提供了多种不同的定时任务工具,可以帮助我们实现自动化操作。本文将会介绍一些Mac中常用…

    编程 2025-04-23
  • Laravel任务调度的探讨

    一、任务调度简介 任务调度是指在应用程序中预定、计划和执行任务的过程。Laravel任务调度器提供了一种友好的方式来注册定期运行的任务,而不需要借助操作系统的Cron语法。任务调度…

    编程 2025-04-22

发表回复

登录后才能评论