当前位置:首页 > 科技  > 软件

Golang异步编程方式和技巧

来源: 责编: 时间:2024-04-24 17:34:54 274观看
导读作者 | zvalhuGolang基于多线程、协程实现,与生俱来适合异步编程,当我们遇到那种需要批量处理且耗时的操作时,传统的线性执行就显得吃力,这时就会想到异步并行处理。下面介绍一些异步编程方式和技巧。一、使用方式1.最简

作者 | zvalhuPhD28资讯网——每日最新资讯28at.com

Golang基于多线程、协程实现,与生俱来适合异步编程,当我们遇到那种需要批量处理且耗时的操作时,传统的线性执行就显得吃力,这时就会想到异步并行处理。下面介绍一些异步编程方式和技巧。PhD28资讯网——每日最新资讯28at.com

PhD28资讯网——每日最新资讯28at.com

一、使用方式

1.最简单的最常用的方式:使用go关键词

func main() { go func() {  fmt.Println("hello world1") }() go func() {  fmt.Println("hello world2") }()}

或者:PhD28资讯网——每日最新资讯28at.com

func main() { go Announce("hello world1") go Announce("hello world2")}func Announce(message string) { fmt.Println(message)}

使用匿名函数传递参数PhD28资讯网——每日最新资讯28at.com

data := "Hello, World!"go func(msg string) {      // 使用msg进行异步任务逻辑处理      fmt.Println(msg)}(data)

这种方式不需要考虑返回值问题,如果要考虑返回值,可以使用下面的方式。PhD28资讯网——每日最新资讯28at.com

2.通过goroutine和channel来实现

ch := make(chan int, 1) // 创建一个带缓冲的channel// ch := make(chan int, 0) // 创建一个无缓冲的channelgo func() {    // 异步任务逻辑    ch <- result // 将结果发送到channel    // 异步任务逻辑    close(ch) // 关闭channel,表示任务完成}()// 在需要的时候从channel接收结果result := <-ch

3.使用sync.WaitGroup

sync.WaitGroup用于等待一组协程完成其任务。通过Add()方法增加等待的协程数量,Done()方法标记协程完成,Wait()方法阻塞直到所有协程完成。PhD28资讯网——每日最新资讯28at.com

var wg sync.WaitGroup// 启动多个协程for i := 0; i < 5; i++ {    wg.Add(1)    go func(index int) {        defer wg.Done()        // 异步任务逻辑    }(i)}// 等待所有协程完成wg.Wait()

4.使用errgroup实现协程组的错误处理

如果想简单获取协程返回的错误,errgroup包很适合,errgroup包是Go语言标准库中的一个实用工具,用于管理一组协程并处理它们的错误。可以使用errgroup.Group结构来跟踪和处理协程组的错误。PhD28资讯网——每日最新资讯28at.com

var eg errgroup.Groupfor i := 0; i < 5; i++ {    eg.Go(func() error {     return errors.New("error")    })    eg.Go(func() error {     return nil    })}if err := eg.Wait(); err != nil {    // 处理错误}

二、一些使用技巧

1.使用channel的range和close操作

range操作可以在接收通道上迭代值,直到通道关闭。可以使用close函数关闭通道,以向接收方指示没有更多的值。PhD28资讯网——每日最新资讯28at.com

ch := make(chan int)go func() {    for i := 0; i < 5; i++ {        ch <- i // 发送值到通道    }    close(ch) // 关闭通道}()// 使用range迭代接收通道的值for val := range ch {    // 处理接收到的值}

2.使用select语句实现多个异步操作的等待

ch1 := make(chan int)ch2 := make(chan string)go func() {    // 异步任务1逻辑    ch1 <- result1}()go func() {    // 异步任务2逻辑    ch2 <- result2}()// 在主goroutine中等待多个异步任务完成select {case res1 := <-ch1:    // 处理结果1case res2 := <-ch2:    // 处理结果2}

3.使用select和time.After()实现超时控制

如果需要在异步操作中设置超时,可以使用select语句结合time.After()函数实现。PhD28资讯网——每日最新资讯28at.com

ch := make(chan int)go func() {    // 异步任务逻辑    time.Sleep(2 * time.Second)    ch <- result}()// 设置超时时间select {case res := <-ch:    // 处理结果case <-time.After(3 * time.Second):    // 超时处理}

4.使用select和time.After()实现超时控制

如果需要在异步操作中设置超时,可以使用select语句结合time.After()函数实现。PhD28资讯网——每日最新资讯28at.com

ch := make(chan int)go func() {    // 异步任务逻辑    time.Sleep(2 * time.Second)    ch <- result}()// 设置超时时间select {case res := <-ch:    // 处理结果case <-time.After(3 * time.Second):    // 超时处理}

5.使用time.Tick()和time.After()进行定时操作

time.Tick()函数返回一个通道,定期发送时间值,可以用于执行定时操作。time.After()函数返回一个通道,在指定的时间后发送一个时间值。PhD28资讯网——每日最新资讯28at.com

tick := time.Tick(1 * time.Second) // 每秒执行一次操作for {    select {    case <-tick:        // 执行定时操作    }}select {case <-time.After(5 * time.Second):    // 在5秒后执行操作}

6.使用sync.Mutex或sync.RWMutex进行并发安全访问

当多个协程并发访问共享数据时,需要确保数据访问的安全性。sync.Mutex和sync.RWMutex提供了互斥锁和读写锁,用于在访问共享资源之前进行锁定,以避免数据竞争。sync.RWMutex是一种读写锁,可以在多个协程之间提供对共享资源的并发访问控制。多个协程可以同时获取读锁,但只有一个协程可以获取写锁。PhD28资讯网——每日最新资讯28at.com

var mutex sync.Mutexvar data int// 写操作,使用互斥锁保护数据mutex.Lock()data = 123mutex.Unlock()// 读操作,使用读锁保护数据//RLock()加读锁时,如果存在写锁,则无法加读锁;当只有读锁或者没有锁时,可以加读锁,读锁可以加载多个mutex.RLock()value := datamutex.RUnlock()var rwMutex sync.RWMutexvar sharedData map[string]string// 读操作,使用rwMutex.RLock读锁保护数据func readData(key string) string {    rwMutex.RLock()    defer rwMutex.RUnlock()    return sharedData[key]}// 写操作,使用rwMutex.Lock写锁保护数据func writeData(key, value string) {    rwMutex.Lock()    defer rwMutex.Unlock()    sharedData[key] = value}

注意:sync.Mutex 的锁是不可以嵌套使用的 sync.RWMutex 的 RLock()是可以嵌套使用的 sync.RWMutex 的 mu.Lock() 是不可以嵌套的 sync.RWMutex 的 mu.Lock() 中不可以嵌套 mu.RLock()PhD28资讯网——每日最新资讯28at.com

7.使用sync.Cond进行条件变量控制

sync.Cond是一个条件变量,用于在协程之间进行通信和同步。它可以在指定的条件满足之前阻塞等待,并在条件满足时唤醒等待的协程。PhD28资讯网——每日最新资讯28at.com

var cond = sync.NewCond(&sync.Mutex{})var ready boolgo func() {    // 异步任务逻辑    ready = true    // 通知等待的协程条件已满足    cond.Broadcast()}()// 在某个地方等待条件满足cond.L.Lock()for !ready {    cond.Wait()}cond.L.Unlock()

8.使用sync.Pool管理对象池

sync.Pool是一个对象池,用于缓存和复用临时对象,可以提高对象的分配和回收效率。PhD28资讯网——每日最新资讯28at.com

type MyObject struct {    // 对象结构}var objectPool = sync.Pool{    New: func() interface{} {        // 创建新对象        return &MyObject{}    },}// 从对象池获取对象obj := objectPool.Get().(*MyObject)// 使用对象// 将对象放回对象池objectPool.Put(obj)

9.使用sync.Once实现只执行一次的操作

sync.Once用于确保某个操作只执行一次,无论有多少个协程尝试执行它,常用于初始化或加载资源等场景。PhD28资讯网——每日最新资讯28at.com

var once sync.Oncevar resource *Resourcefunc getResource() *Resource {    once.Do(func() {        // 执行初始化资源的操作,仅执行一次        resource = initResource()    })    return resource}// 在多个协程中获取资源go func() {    res := getResource()    // 使用资源}()go func() {    res := getResource()    // 使用资源}()

10.使用sync.Once和context.Context实现资源清理

可以结合使用sync.Once和context.Context来确保在多个协程之间只执行一次资源清理操作,并在取消或超时时进行清理。PhD28资讯网——每日最新资讯28at.com

var once sync.Oncefunc cleanup() {    // 执行资源清理操作}func doTask(ctx context.Context) {    go func() {        select {        case <-ctx.Done():            once.Do(cleanup) // 只执行一次资源清理        }    }()    // 异步任务逻辑}

11.使用sync.Map实现并发安全的映射

sync.Map是Go语言标准库中提供的并发安全的映射类型,可在多个协程之间安全地进行读写操作。PhD28资讯网——每日最新资讯28at.com

var m sync.Map// 存储键值对m.Store("key", "value")// 获取值if val, ok := m.Load("key"); ok {    // 使用值}// 删除键m.Delete("key")

12.使用context.Context进行协程管理和取消

context.Context用于在协程之间传递上下文信息,并可用于取消或超时控制。可以使用context.WithCancel()创建一个可取消的上下文,并使用context.WithTimeout()创建一个带有超时的上下文。PhD28资讯网——每日最新资讯28at.com

ctx, cancel := context.WithCancel(context.Background())go func() {    // 异步任务逻辑    if someCondition {        cancel() // 取消任务    }}()// 等待任务完成或取消select {case <-ctx.Done():    // 任务被取消或超时}

13.使用context.WithDeadline()和context.WithTimeout()设置截止时间

context.WithDeadline()和context.WithTimeout()函数可以用于创建带有截止时间的上下文,以限制异步任务的执行时间。PhD28资讯网——每日最新资讯28at.com

func doTask(ctx context.Context) {    // 异步任务逻辑    select {    case <-time.After(5 * time.Second):        // 超时处理    case <-ctx.Done():        // 上下文取消处理    }}func main() {    ctx := context.Background()    ctx, cancel := context.WithTimeout(ctx, 3*time.Second)    defer cancel()    go doTask(ctx)    // 继续其他操作}

14.使用context.WithValue()传递上下文值

context.WithValue()函数可用于在上下文中传递键值对,以在协程之间共享和传递上下文相关的值。PhD28资讯网——每日最新资讯28at.com

type keyContextValue stringfunc doTask(ctx context.Context) {    if val := ctx.Value(keyContextValue("key")); val != nil {        // 使用上下文值    }}func main() {    ctx := context.WithValue(context.Background(), keyContextValue("key"), "value")    go doTask(ctx)    // 继续其他操作}

15.使用atomic包进行原子操作

atomic包提供了一组函数,用于实现原子操作,以确保在并发环境中对共享变量的读写操作是原子的。PhD28资讯网——每日最新资讯28at.com

var counter int64func increment() {    atomic.AddInt64(&counter, 1)}func main() {    var wg sync.WaitGroup    for i := 0; i < 100; i++ {        wg.Add(1)        go func() {            defer wg.Done()            increment()        }()    }    wg.Wait()    fmt.Println("Counter:", counter)}

本文链接:http://www.28at.com/showinfo-26-85231-0.htmlGolang异步编程方式和技巧

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: React 18的并发渲染:颠覆传统的性能飞跃

下一篇: 讨论万能头文件&lt;bits/stdc++.h&gt; 在C++中的使用

标签:
  • 热门焦点
  • 对标苹果的灵动岛 华为带来实况窗功能

    继苹果的灵动岛之后,华为也在今天正式推出了“实况窗”功能。据今天鸿蒙OS 4.0的现场演示显示,华为的实况窗可以更高效的展现出实时通知,比如锁屏上就能看到外卖、打车、银行
  • JavaScript 混淆及反混淆代码工具

    介绍在我们开始学习反混淆之前,我们首先要了解一下代码混淆。如果不了解代码是如何混淆的,我们可能无法成功对代码进行反混淆,尤其是使用自定义混淆器对其进行混淆时。什么是混
  • 线程通讯的三种方法!通俗易懂

    线程通信是指多个线程之间通过某种机制进行协调和交互,例如,线程等待和通知机制就是线程通讯的主要手段之一。 在 Java 中,线程等待和通知的实现手段有以下几种方式:Object 类下
  • 从 Pulsar Client 的原理到它的监控面板

    背景前段时间业务团队偶尔会碰到一些 Pulsar 使用的问题,比如消息阻塞不消费了、生产者消息发送缓慢等各种问题。虽然我们有个监控页面可以根据 topic 维度查看他的发送状态,
  • JavaScript学习 -AES加密算法

    引言在当今数字化时代,前端应用程序扮演着重要角色,用户的敏感数据经常在前端进行加密和解密操作。然而,这样的操作在网络传输和存储中可能会受到恶意攻击的威胁。为了确保数据
  • 虚拟键盘 API 的妙用

    你是否在遇到过这样的问题:移动设备上有一个固定元素,当激活虚拟键盘时,该元素被隐藏在了键盘下方?多年来,这一直是 Web 上的默认行为,在本文中,我们将探讨这个问题、为什么会发生
  • 拼多多APP上线本地生活入口,群雄逐鹿万亿市场

    Tech星球(微信ID:tech618)文 | 陈桥辉 Tech星球独家获悉,拼多多在其APP内上线了&ldquo;本地生活&rdquo;入口,位置较深,位于首页的&ldquo;充值中心&rdquo;内,目前主要售卖美食相关的
  • 阿里大调整

    来源:产品刘有媒体报道称,近期淘宝天猫集团启动了近年来最大的人力制度改革,涉及员工绩效、层级体系等多个核心事项,目前已形成一个初步的&ldquo;征求意见版&rdquo;:1、取消P序列
  • 三星获批量产iPhone 15全系屏幕:苹果史上最惊艳直屏

    按照惯例,苹果将继续在今年9月举办一年一度的秋季新品发布会,有传言称发布会将于9月12日举行,届时全新的iPhone 15系列将正式与大家见面,不出意外的话
Top