首页 > 其他分享 >Go语言中的并发模式

Go语言中的并发模式

时间:2024-11-03 18:57:22浏览次数:1  
标签:jobs 语言 fmt goroutine 并发 func time Go

Go语言中的并发模式

原创 Go 源自开发者    2024年11月01日 23:47 广东 听全文 源自开发者 专注于提供关于Go语言的实用教程、案例分析、最新趋势,以及云原生技术的深度解析和实践经验分享。 373篇原创内容 公众号

Go语言以其并发性和轻量级的goroutine而闻名,学习如何使用和处理它们是最具挑战性的任务。在本文中,我将展示一些并发模式及其使用场景,以帮助您识别所需场景的模式。

1. Goroutine

package main

import (
    "fmt"
    "time"
)

func main() {
    go sayHello() // 启动goroutine
    time.Sleep(1 * time.Second) // 等待goroutine完成
}

func sayHello() {
    fmt.Println("Hello, World!")
}

使用场景

当您需要执行非阻塞操作时,例如在Web服务器中处理请求或执行后台任务。

优点

  • 轻量级且易于启动。
  • 提供简单的并发性,无需复杂的结构。

缺点

  • 如果共享数据处理不当,可能导致竞争条件。
  • 由于执行流程非线性,调试可能更加复杂。

2. 通道(Channel)

package main

import (
    "fmt"
)

func main() {
    ch := make(chan string) // 创建通道

    go func() {
        ch <- "Hello from Goroutine!" // 发送数据到通道
    }()

    message := <-ch // 从通道接收数据
    fmt.Println(message)
}

使用场景

在goroutine之间通信或同步执行。

优点

  • 在goroutine之间安全通信。
  • 简单的同步机制。

缺点

  • 如果过度使用或误用,可能引入复杂性。
  • 如果通道处理不当,可能发生死锁。

3. 工作池(Worker Pool)

package main

import (
    "fmt"
    "sync"
)

type Job struct {
    ID int
}

func worker(id int, jobs <-chan Job, wg *sync.WaitGroup) {
    defer wg.Done()
    for job := range jobs {
        fmt.Printf("Worker %d processing job %d\n", id, job.ID)
    }
}

func main() {
    const numWorkers = 3
    jobs := make(chan Job, 10) // 缓冲通道
    var wg sync.WaitGroup

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

    for j := 1; j <= 5; j++ {
        jobs <- Job{ID: j} // 发送任务到通道
    }
    close(jobs) // 关闭任务通道
    wg.Wait() // 等待所有工作完成
}

使用场景

当您有许多任务可以并发处理,但希望限制并发操作的数量时。

优点

  • 通过控制并发goroutine的数量来限制资源使用。
  • 易于高效地处理大量任务。

缺点

  • 比简单的goroutine实现更复杂。
  • 需要仔细管理任务分配和完成。

4. 扇出扇入(Fan-Out, Fan-In)

package main

import (
    "fmt"
    "sync"
)

func worker(id int, jobs <-chan int, results chan<- int, wg *sync.WaitGroup) {
    defer wg.Done()
    for job := range jobs {
        results <- job * 2 // 处理任务
    }
}

func main() {
    jobs := make(chan int, 10)
    results := make(chan int, 10)
    var wg sync.WaitGroup

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

    go func() {
        wg.Wait()
        close(results) // 完成后关闭结果通道
    }()

    for j := 1; j <= 5; j++ {
        jobs <- j // 发送任务
    }
    close(jobs) // 关闭任务通道

    for result := range results {
        fmt.Println("Result:", result) // 收集结果
    }
}

使用场景

当您需要将工作分配给多个goroutine并整合结果时。

优点

  • 高效地平衡多个工作者之间的工作负载。
  • 简化结果收集。

缺点

  • 由于多个通道,稍微复杂一些。
  • 需要仔细管理同步。

5. 用于取消的上下文(Context for Cancellation)

package main

import (
    "context"
    "fmt"
    "time"
)

func doWork(ctx context.Context) {
    for {
        select {
        case <-ctx.Done():
            fmt.Println("Work canceled")
            return
        default:
            fmt.Println("Working...")
            time.Sleep(500 * time.Millisecond) // 模拟工作
        }
    }
}

func main() {
    ctx, cancel := context.WithCancel(context.Background())

    go doWork(ctx)

    time.Sleep(2 * time.Second) // 让它工作一段时间
    cancel() // 取消工作
    time.Sleep(1 * time.Second) // 等待取消
}

使用场景

当您需要管理goroutine的取消或超时时。

优点

  • 提供一种结构化的方式来取消goroutine。
  • 可以使用单个上下文管理多个goroutine。

缺点

  • 如果管理不当,可能会使逻辑复杂化。
  • 需要理解上下文传播。

6. 管道(Pipeline)

package main

import (
    "fmt"
)

func square(input <-chan int, output chan<- int) {
    for num := range input {
        output <- num * num // 平方数
    }
    close(output) // 完成后关闭输出
}

func main() {
    input := make(chan int)
    output := make(chan int)

    go square(input, output)

    for i := 1; i <= 5; i++ {
        input <- i // 发送数字
    }
    close(input) // 关闭输入通道

    for result := range output {
        fmt.Println("Squared:", result) // 打印结果
    }
}

使用场景

当您希望分阶段处理数据时。

优点

  • 促进模块化和关注点分离。
  • 更容易管理和理解数据流。

缺点

  • 随着阶段的增多,可能变得复杂。
  • 需要仔细管理通道。

7. 速率限制(Rate Limiting)

package main

import (
    "fmt"
    "time"
)

func main() {
    ticker := time.NewTicker(1 * time.Second) // 设置速率限制
    defer ticker.Stop()

    go func() {
        for range ticker.C {
            fmt.Println("Tick: Doing work...")
            // 在这里执行工作
        }
    }()

    // 模拟工作5秒
    time.Sleep(5 * time.Second)
}

使用场景

当您需要限制操作速率时,例如API调用。

优点

  • 控制操作频率的简单有效方法。
  • 减少资源争用。

缺点

  • 如果限制过于严格,可能会延迟处理。
  • 需要仔细配置速率限制。

8. Select语句

package main

import (
    "fmt"
    "time"
)

func main() {
    ch1 := make(chan string)
    ch2 := make(chan string)

    go func() {
        time.Sleep(2 * time.Second)
        ch1 <- "Result from channel 1"
    }()

    go func() {
        time.Sleep(1 * time.Second)
        ch2 <- "Result from channel 2"
    }()

    select {
    case msg1 := <-ch1:
        fmt.Println(msg1)
    case msg2 := <-ch2:
        fmt.Println(msg2)
    case <-time.After(3 * time.Second):
        fmt.Println("Timeout!")
    }
}

使用场景

当您需要等待多个通道并根据哪个通道首先接收到数据来执行操作时。

优点

  • 提供处理多个异步操作的方法。
  • 可以有效地实现超时。

缺点

  • 如果处理不当,可能导致复杂的逻辑。
  • 需要仔细处理所有情况以避免信号丢失。

总结

这些模式是编写Go语言并发程序的基础。每种模式都有其使用场景、优点和缺点,您可能会发现结合多种模式可以为您的应用程序提供最佳解决方案。仔细考虑应用程序的具体需求,并选择合适的模式。

图片


文章精选

使用 Go 语言连接并操作 SQLite 数据库

Go语言官方团队推荐的依赖注入工具

替代zap,Go语言官方实现的结构化日志包

Go语言常见错误 | 不使用function option模式

必看| Go语言项目结构最佳实践

 

源自下载,,, 点击添加进交流群,免费领取Go语言学习资料! 小程序

 

Golang207 Golang · 目录 上一篇在 Docker 中运行 Golang 应用程序 阅读原文 阅读 1278   ​

标签:jobs,语言,fmt,goroutine,并发,func,time,Go
From: https://www.cnblogs.com/cheyunhua/p/18523784

相关文章

  • (2)---【C语言】【GL库】【计算机图形学】DEV C++ 平台openGL库 下的画线图案设计 房
     上篇上手实践  运行结果  实现代码#include<windows.h>#include<GL/glut.h>#defineGLUT_DISABLE_ATEXIT_HACK//处理不同系统宏//星状结构函数,添加了几何中心坐标,半径,叶片宽度占比,叶片数量--------------------------------//绘制内部星状结构基本元素的......
  • 开发 Android 应用时,可以使用以下几种编程语言:
    开发Android应用时,可以使用以下几种编程语言:###1.**Java**-**描述**:Java是Android开发的传统语言,广泛使用,并且有丰富的文档和社区支持。-**特点**:面向对象,适合大型应用开发。AndroidSDK和大多数库均支持Java。###2.**Kotlin**-**描述**:Kotlin是官方推荐的Andro......
  • Java 编程:强大的跨平台开发语言
    Java是一种广泛使用的面向对象的编程语言,由SunMicrosystems公司(现已被Oracle公司收购)于1995年发布。Java的设计目标是“一次编写,到处运行”(WriteOnce,RunAnywhere),这使得它成为一种非常强大且灵活的编程语言,尤其适合企业级应用和互联网开发。  Java的特点1.*......
  • C语言:函数
    一.自定义函数自定义函数形式如下:ret_type fun_name(形式参数){}ps:1.ret_type是函数返回类型,有时候是void,表示什么都不返回2.fun_name是函数名,尽量清楚明了3.括号中放的是形式参数,有时候是void,表示没有参数,如果有参数记得加入参数的类型和......
  • Google Guava 发布订阅模式/生产消费者模式 使用详情
    目录Guava介绍应用场景举例1.引入Maven依赖 2.自定义Event事件类3.定义EventListener事件订阅者4.定义EventBus事件总线5.定义Controller进行测试Guava介绍        Guava是一组来自Google的核心Java库,里面包括新的集合类型(例如Mu......
  • Java并发编程
    目录Java并发编程原子性可见性有序性导致并发程序的根本原因是什么原子性和锁区别,加锁是为了什么为什么要加锁锁问题死锁(DeadLock)无锁有锁Synchronized对象在内存中的实现偏向锁/轻量级锁/重量级锁锁升级如何实现可重入性不可中断性同步方法同步代码缺......
  • CSGO人物yolo数据集 3200张+ 含300轮训练结果
    介绍本次分享的是一个专为CSGO(反恐精英:全球攻势)设计的YOLO数据集,包含3200张已标注好的人物图像。为了帮助研究者和开发者更好地利用这一数据集,站长已经进行了300轮的训练,确保模型性能的可靠性。您可以选择自己进行训练,或者直接使用我们训练好的模型,快速开展目标检测任务。训......
  • (开题报告)django+vue校园二手交易app论文+源码
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景在当今数字化时代背景下,高校作为知识创新与人才培养的摇篮,其内部经济活动日益频繁,尤其是学生对于二手物品的交换需求日益增长。传统的线下......
  • C程序设计语言 第一章 导言
    1.1入门学习一门新程序设计语言的唯一途径就是使用它编写程序。对于所有语言的初学者来说编写的第一个程序几乎都是相同的,即请打印出下列内容hello,world尽管这个练习很简单,但对于初学语言的人来说,它仍然可能成为一大障碍,因为要实现这个目的,我们首先必须编写程序文本,然后......
  • C语言简介
    C语言在‌编程中的基础地位‌C语言是一门非常基础的编程语言,具有高效、灵活、可移植等特点。它的语法简单明了,易于学习和理解。C语言的设计思想和编程范式对程序员的编程思路产生了深远的影响,使程序员更加注重程序的结构化设计、效率和性能、可移植性等方面。C语言对编程能力......