Go语言常见的并发模式

Go语言常见的并发模式

并发不是并行 并发关注的是程序的设计层面,并发的程序也可以顺序执行,在多核CPU上才可能真正同时的运行,并行关注的是程序的运行层面,如GPU中对图像处理都会有大量的并行运算。

Go语言将其并发编程哲学Slogan:不要通过共享内存来通信,而应通过通信来共享内存。

func main() {
    var (
        mu sync.Mutex
        i  = 0
    )
    mu.Lock()
    go func() {
        for x := 0; x < 10; x++ {
            i++
        }
    }()
    mu.Unlock()
}

func main() {
    done := make(chan int, 1)

    go func() {
        fmt.Println("hello world")
        done <- 0 1 }() <-done } 对于带缓冲的channel,对于channel的第k个接收完成操作发生在第k+c个发送操作完成之前,其中c是channel的缓存大小。虽然管道是带缓存的 func main() { done :="make(chan" int, 10) 缓存为 for i < cap(done); i++ go func(x int) fmt.println("x=", x)
            done <- 1
        }(i)
    }

    //&#x7B49;&#x5F85; 10 &#x4E2A;goroutine
    for i := 0; i < cap(done); i++ {
        <-done
    }
}

func main() {
    var wg sync.WaitGroup

    for i := 0; i < 10; i++ {
        wg.Add(1) //&#x5728;&#x5F00;&#x542F;goroutine &#x524D;

        go func(x int) {
            fmt.Println(" x=", x)
            wg.Done()
        }(i)
    }

    wg.Wait()
}
</code></pre><p>&#x751F;&#x4EA7;&#x6D88;&#x8D39;&#x662F;&#x5F02;&#x6B65;&#x7684;&#x4E24;&#x4E2A;&#x8FC7;&#x7A0B;&#xFF0C;&#x751F;&#x4EA7;&#x8005;&#x751F;&#x4EA7;&#x6570;&#x636E;&#xFF0C;&#x7136;&#x540E;&#x653E;&#x5230;&#x6210;&#x679C;&#x961F;&#x5217;&#x4E2D;&#xFF0C;&#x540C;&#x65F6;&#x6D88;&#x8D39;&#x8005;&#x4ECE;&#x6210;&#x679C;&#x961F;&#x5217;&#x4E2D;&#x6765;&#x6D88;&#x8D39;&#x8FD9;&#x4E9B;&#x6570;&#x636E;&#xFF0C;&#x5F53;&#x6210;&#x679C;&#x961F;&#x5217;&#x4E2D;&#x6CA1;&#x6709;&#x6570;&#x636E;&#x65F6;&#xFF0C;&#x6D88;&#x8D39;&#x8005;&#x5C31;&#x8FDB;&#x5165;&#x9965;&#x997F;&#x7684;&#x7B49;&#x5F85;&#x4E2D;&#xFF1B;&#x800C;&#x5F53;&#x6210;&#x679C;&#x961F;&#x5217;&#x4E2D;&#x6570;&#x636E;&#x5DF2;&#x6EE1;&#x65F6;&#xFF0C;&#x751F;&#x4EA7;&#x8005;&#x5219;&#x9700;&#x8981;&#x7B49;&#x5F85;&#x6D88;&#x8D39;&#x8005;&#x6D88;&#x8D39;&#x6570;&#x636E;&#x3002;</p><pre><code>// &#x751F;&#x4EA7;&#x8005;
func Producer(out chan<- int) {
    for i := 0; ; i++ {
        out <- i * i
    }
}

// &#x6D88;&#x8D39;&#x8005;
func Consumer(in <-chan int) {
    for v := range in {
        fmt.Println(v)
    }
}
func main() {
    ch := make(chan int, 10)
    go Producer(ch)
    go Consumer(ch)
    time.Sleep(2 * time.Second)
}
</code></pre><p>&#x53D1;&#x5E03;&#x8BA2;&#x9605;&#x6A21;&#x578B;&#x901A;&#x5E38;&#x88AB;&#x7B80;&#x5199;&#x4E3A;pub/sub&#x6A21;&#x578B;&#x3002;&#x5728;&#x8FD9;&#x4E2A;&#x6A21;&#x578B;&#x4E2D;&#xFF0C;&#x6D88;&#x606F;&#x751F;&#x4EA7;&#x8005;&#x6210;&#x4E3A;&#x53D1;&#x5E03;&#x8005;&#xFF08;publisher&#xFF09;&#xFF0C;&#x800C;&#x6D88;&#x606F;&#x6D88;&#x8D39;&#x8005;&#x5219;&#x6210;&#x4E3A;&#x8BA2;&#x9605;&#x8005;&#xFF08;subscriber&#xFF09;&#xFF0C;&#x751F;&#x4EA7;&#x8005;&#x548C;&#x6D88;&#x8D39;&#x8005;&#x662F;M:N&#x7684;&#x5173;&#x7CFB;&#x3002;&#x5728;&#x4F20;&#x7EDF;&#x751F;&#x4EA7;&#x8005;&#x548C;&#x6D88;&#x8D39;&#x8005;&#x6A21;&#x578B;&#x4E2D;&#xFF0C;&#x662F;&#x5C06;&#x6D88;&#x606F;&#x53D1;&#x9001;&#x5230;&#x4E00;&#x4E2A;&#x961F;&#x5217;&#x4E2D;&#xFF0C;&#x800C;&#x53D1;&#x5E03;&#x8BA2;&#x9605;&#x6A21;&#x578B;&#x5219;&#x662F;&#x5C06;&#x6D88;&#x606F;&#x53D1;&#x5E03;&#x7ED9;&#x4E00;&#x4E2A;&#x4E3B;&#x9898;</p><p>&#x53EF;&#x4EE5;&#x901A;&#x8FC7;&#x5E26;&#x7F13;&#x5B58;Channel&#x7684;&#x4F7F;&#x7528;&#x91CF;&#x548C;&#x6700;&#x5927;&#x5BB9;&#x91CF;&#x6BD4;&#x4F8B;&#x6765;&#x5224;&#x65AD;&#x7A0B;&#x5E8F;&#x8FD0;&#x884C;&#x7684;&#x5E76;&#x53D1;&#x7387;</p><pre><code>func main() {
    control := make(chan interface{}, 3)
    done := make(chan struct{}, 10)
    for i := 1; i <= 10; i++ {
        control <- i
        go func(j int) {
            fmt.Printf(" i: %d, time: %d\n", j, time.now().unix()) time.sleep(time.second) <-control <- struct{}{} }(i) code></->

Go语言中不同Goroutine之间主要依靠管道进行通信和同步。要同时处理多个管道的发送或接收操作,我们需要使用select关键字。当select有多个分支时,会随机选择一个可用的管道分支,如果没有可用的管道分支则选择default分支,否则会一直保存阻塞状态

select {
case v := <-in: fmt.println(v) case <-time.after(time.second): return 超时 default: 没有数据 } < code></-in:>

标准库context包,用来简化对于处理单个请求的多个Goroutine之间与请求域的数据、超时和退出等操作

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go worker(ctx, &wg)
    }

    time.Sleep(time.Second)
    cancel()

    wg.Wait()
}

func worker(ctx context.Context, wg *sync.WaitGroup) error {
    defer wg.Done()
    for {
        select {
        default:
            fmt.Println("hello")
        case <-ctx.done(): fmt.println("ctx done") return ctx.err() } < code></-ctx.done():>

Original: https://www.cnblogs.com/arvinhuang/p/15220994.html
Author: 平凡键客
Title: Go语言常见的并发模式

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/620177/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • mysql中文乱码记录

    0.中文乱码 1.查看mysql中表结构 show create table log_data charset为utf8,代码端:通过gorm修改 在创建表时候修改( 这里在连接数…

    数据库 2023年5月24日
    092
  • 第八章:变量、常量和基础类型

    本篇翻译自《Practical Go Lessons》 Chapter 8: Variables, constants and basic types 1 你将在本章中学到什么? …

    数据库 2023年6月6日
    0128
  • postman结合newman生成测试报告

    1. cmd窗口安装newman npm install -g newman 2. cmd窗口安装newman-html报告 nnpm install -g newman-repo…

    数据库 2023年6月14日
    0100
  • [springmvc]拦截器功能

    11.拦截器 只会拦截controller的请求,对于静态资源不处理 被spring代理的拦截器实现只需要两步: 1.实现一个拦截器类 package com.spring.con…

    数据库 2023年6月16日
    080
  • js异步编程终级解决方案 async/await

    在最新的ES7(ES2017)中提出的前端异步特性:async、await。 async、await是什么 async顾名思义是”异步”的意思,async用…

    数据库 2023年6月9日
    087
  • Git命令列表–git-config

    git config 查看、编辑Git的配置文件 配置文件的范围和语法 $ git config usage: it config [] Config file location …

    数据库 2023年6月11日
    082
  • 主从复制架构直接转换MGR(manual)

    IP port role info 192.168.188.81 3316 node1 master 192.168.188.82 3316 node2 slave1 192.16…

    数据库 2023年6月16日
    0222
  • MyBatis(三)-动态SQL

    1、if 注意:test里面使用的参数,可以是mybatis的默认参数,也可以是实体属性名,但是不能是没有指定别名的参数名(尤其是单个参数,也必须起别名,否则异常); 单独使用if…

    数据库 2023年6月16日
    091
  • 数据库原理二—MySQL事务与锁

    数据库事务的四大特性 原子性A 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用 一致性C 执行事务前后,数据保持一致,多个事务对同一个数据读取…

    数据库 2023年6月6日
    071
  • day03-拉取在线用户功能

    多用户即时通讯系统03 4.编码实现02 4.2功能实现-拉取在线用户 4.2.1思路分析 客户端想要知道在线用户列表,就要向服务器发送请求(Message),因为只有服务器端保持…

    数据库 2023年6月11日
    0166
  • Mysql 实现数据库读写分离

    一、Amoeba 是什么 Amoeba(变形虫)项目,专注 分布式数据库 proxy 开发。座落与Client、DB Server(s)之间。对客户端透明。具有负载均衡、高可用性、…

    数据库 2023年6月14日
    084
  • Nginx负载均衡

    Nginx负载均衡 负载均衡概述 早期的网站流量和业务功能都比较简单,单台服务器足以满足基本的需求,但是随着互联网的发展,业务流量越来越大并且业务逻辑也跟着越来越复杂,单台服务器的…

    数据库 2023年6月6日
    086
  • 小心陷入MySQL索引的坑

    索引可以说是数据库中的一个大心脏了,如果说一个数据库少了索引,那么数据库本身存在的意义就不大了,和普通的文件没什么两样。所以说一个好的索引对数据库系统尤其重要,今天来说说MySQL…

    数据库 2023年6月6日
    095
  • 23种设计模式之中介者模式(Mediator)

    文章目录 概述 中介者模式的优缺点 中介者模式的使用场景 中介者模式的结构和实现 * 模式结构 模式实现 总结 概述 用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式…

    数据库 2023年6月6日
    098
  • MySQL触发器

    触发器 先来个实际的案例 触发器概述 和存储过程一样,都是嵌入在MySQL服务器中的一段程序 触发器由 事件触发,比如INSERT ,UPDATE 等用户的动作或触发某项行为,自动…

    数据库 2023年5月24日
    098
  • 数据库设计案例

    简单构建设计数据库 数据库设计案例 描述:简单构建设计数据库 sql代码实现 /* 数据库设计案例 */ — 音乐表 CREATE TABLE Music ( title VAR…

    数据库 2023年5月24日
    0122
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球