concurrency 并行编程

news2024/11/17 16:34:21

Goroutine

go语言的魅力所在,高并发。

线程是操作系统调度的一种执行路径,用于在处理器执行我们在函数中编写的代码。一个进程从一个线程开始,即主线程,当该线程终止时,进程终止。这是因为主线程是应用程序的原点。然后,主线程可以依次启动更多的线程,而这些线程可以启动更多的线程。

并发不是并行。并行是指两个或多个线程同时在不同的处理器执行代码。如果将运行时配置为使用多个逻辑处理器,则调度程序将在这些逻辑处理器之间分配 goroutine,这将导致 goroutine 在不同的操作系统线程上运行。但是,要获得真正的并行性,您需要在具有多个物理处理器的计算机上运行程序。否则,goroutine 将针对单个物理处理器并发运行,即使 Go 运行时使用多个逻辑处理器。

注意:① 空的 select{} 会永远进行 阻塞

② 如果当前的goroutine要执行但是需要等待另一个goroutine执行完毕才行,这时候就要把另一个goroutine的事情拿来自己做。

③ 使用goroutine考虑两个问题,一是它什么时候结束,二是你有没有一个方法让它结束

这里展示一个较好例子:

Memory model

go 的内存模型,个人总结:只要是多线程就不要觉得自己太聪明,使用”锁",确保操作事物的原子性,因为多线程之间的调度过程中,cpu,线程为了最大限度的性能,有可能改变不同线程之间关于整体事物的逻辑执行顺序,导致结果出现不可测性。指针copy的方法,指针是一个原子性,但是并不满足 single machine. 当然如果你只是单线程,那么这些忧虑不用考虑

为了说明读和写的必要条件,我们定义了先行发生(Happens Before)。如果事件 e1 发生在 e2 前,我们可以说 e2 发生在 e1 后。如果 e1不发生在 e2 前也不发生在 e2 后,我们就说 e1 和 e2 是并发的。
在单一的独立的 goroutine 中先行发生的顺序即是程序中表达的顺序。

  • 当下面条件满足时,对变量 v 的读操作 r 是被允许看到对 v 的写操作 w 的:
    • r 不先行发生于 w
    • 在 w 后 r 前没有对 v 的其他写操作
  • 为了保证对变量 v 的读操作 r 看到对 v 的写操作 w,要确保 w 是 r 允许看到的唯一写操作。即当下面条件满足时,r 被保证看到 w:
    • w 先行发生于 r
    • 其他对共享变量 v 的写操作要么在 w 前,要么在 r 后。


这一对条件比前面的条件更严格,需要没有其他写操作与 w 或 r 并发发生。

Package sync

data race : 线程竞争,在线程模型中Go 没有显式地使用锁来协调对共享数据的访问,而是鼓励使用 chan 在 goroutine 之间传递对数据的引用。这种方法确保在给定的时间只有一个 goroutine 可以访问数据。

go buid -race go test -race

i++是原子性操作吗? 不是,i++的底层是三行代码,并不是原子性。

Copy-On-Write 思路在微服务降级或者 local cache 场景中经常使用。写时复制指的是,写操作时候复制全量老数据到一个新的对象中,携带上本次新写的数据,之后利用原子替换(atomic.Value),更新调用者的变量。来完成无锁访问共享数据。这也是 Redis 进行写操作来更改数据的一种方法。

Mutex

  • go的几种 Mutex 锁的实现:
    • Barging. 这种模式是为了提高吞吐量,当锁被释放时,它会唤醒第一个等待者,然后把锁给第一个等待者或者给第一个请求锁的人。
    • Handsoff. 当锁释放时候,锁会一直持有直到第一个等待者准备好获取锁。它降低了吞吐量,因为锁被持有,即使另一个 goroutine 准备获取它。(一个互斥锁的 handsoff 会完美地平衡两个goroutine 之间的锁分配,但是会降低性能,因为它会迫使第一个 goroutine 等待锁。)
    • Spinning. 自旋在等待队列为空或者应用程序重度使用锁时效果不错。parking 和 unparking goroutines 有不低的性能成本开销,相比自旋来说要慢得多。

errgroup

实际生活中我们的errgroup使用的更多一些,用几个gooroutine 去进行分布处理业务,然后通过sync进行控制管理各个分支,把最后的数据再集合起来。 sync.waitGroup()

Chan

各个goroutine通过chan管道来进行实时通信。

channels 是一种类型安全的消息队列,充当两个 goroutine 之间的管道,将通过它同步的进行任意资源的交换。chan 控制 goroutines 交互的能力从而创建了 Go 同步机制。当创建的 chan 没有容量时,称为无缓冲通道。反过来,使用容量创建的 chan 称为缓冲通道。

无缓冲chan

ch := make(chan struct{})
无缓冲 chan 没有容量,因此进行任何交换前需要两个 goroutine 同时准备好。当 goroutine 试图将一个资源发送到一个无缓冲的通道并且没有goroutine 等待接收该资源时,该通道将锁住发送 goroutine 并使其等待。当 goroutine 尝试从无缓冲通道接收,并且没有 goroutine 等待发送资源时,该通道将锁住接收 goroutine 并使其等待。
意思就是双方都得准备好才能进行下去 , 无缓冲信道的本质是保证同步。

  • Receive 先于 Send 发生。
  • 好处: 100% 保证能收到。
  • 代价: 延迟时间未知。

有缓冲的chan

buffered channel 具有容量,因此其行为可能有点不同。当 goroutine 试图将资源发送到缓冲通道,而该通道已满时,该通道将锁住 goroutine并使其等待缓冲区可用。如果通道中有空间,发送可以立即进行,goroutine 可以继续。当goroutine 试图从缓冲通道接收数据,而缓冲通道为空时,该通道将锁住 goroutine 并使其等待资源被发送。

  • Send 先于 Receive 发生。
  • 好处: 延迟更小。
  • 代价: 不保证数据到达,越大的 buffer,越小的保障到达。buffer = 1 时,给你延迟一个消息的保障。

Context

context 的使用因该是贯穿全过程,而不是被把它放到一个对象结构体中去使用

context.WithValue() : 用于创建一个context对象

context.WithValue 方法允许上下文携带请求范围的数据。这些数据必须是安全的,以便多个 goroutine 同时使用。这里的数据,更多是面向请求的元数据,不应该作为函数的可选参数来使用(比如 context 里面挂了一个sql.Tx 对象,传递到 data 层使用),因为元数据相对函数参数更加是隐含的,面向请求的。而参数是更加显示的。

同一个 context 对象可以传递给在不同 goroutine 中运行的函数;上下文对于多个 goroutine 同时使用是安全的。对于值类型最容易犯错的地方,在于 context value 应该是 immutable 的,每次重新赋值应该是新的 context,即: context.WithValue(ctx, oldvalue)

比如 染色,API 重要性,Trace

注意选择使用 copy-on-write 的思路,解决跨多个 goroutine 使用数据、修改数据的场景。

COW: 从 ctx1 中获取 map1(可以理解为 v1 版本的 map 数据)。构建一个新的 map 对象 map2,复制所有 map1 数据,同时追加新的数据 “k2”: “v2” 键值对,使用 context.WithValue 创建新的 ctx2,ctx2 会传递到其他的 goroutine 中。这样各自读取的副本都是自己的数据,写行为追加的数据,在 ctx2 中也能完整读取到,同时也不会污染 ctx1 中的数据。

COW就是 copy-on-write

当一个 context 被取消时,从它派生的所有 context 也将被取消。WithCancel(ctx) 参数 ctx 认为是 parent ctx,在内部会进行一个传播关系链的关联。Done() 返回 一个 chan,当我们取消某个parent context, 实际上上会递归层层 cancel 掉自己的 child context 的 done chan 从而让整个调用链中所有监听 cancel 的 goroutine 退出。

如果要实现一个超时控制,通过上面的 context 的 parent/child 机制,其实我们只需要启动一个定时器,然后在超时的时候,直接将当前的 context 给 cancel 掉,就可以实现监听在当前和下层的额 context.Done() 的 goroutine 的退出。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1697607.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LeetCode题练习与总结:二叉树的层序遍历Ⅱ--107

一、题目描述 给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历) 示例 1: 输入:root [3,9,20,null,null,15,7] 输出:[…

springboot3微服务下结合springsecurity的认证授权实现

1. 简介 在微服务架构中,系统被拆分成许多小型、独立的服务,每个服务负责一个功能模块。这种架构风格带来了一系列的优势,如服务的独立性、弹性、可伸缩性等。然而,它也带来了一些挑战,特别是在安全性方面。这时候就体…

YOLOv5改进策略:Focaler-IoU损失函数改进

文章目录 1、前言2、摘要3、Focaler-IoU:4、代码实现5、目标检测系列文章 1、前言 ​ 目标检测是计算机视觉的基本任务之一,旨在识别图像中的目标并定位其位置。目标检测算法可分为基于锚点和无锚点的方法。基于锚点的方法包括Faster R-CNN、YOLO系列、…

数据结构 —— 栈 与 队列

1.栈 1.1栈的结构和概念 栈(Stack)是一种特殊的线性数据结构,它遵循后进先出(LIFO,Last In First Out)的原则。栈只允许在一端插入和删除数据,这一端被称为栈顶(top)&a…

Hudi 多表摄取工具 HoodieMultiTableStreamer 配置方法与示例

博主历时三年精心创作的《大数据平台架构与原型实现:数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行,点击《重磅推荐:建大数据平台太难了!给我发个工程原型吧!》了解图书详情,…

基于SpringBoot和Mybatis实现的留言板案例

目录 一、需求及界面展示 二、准备工作 引入依赖 .yml文件相关配置 数据库数据准备 三、编写后端代码 需求分析 代码结构 Model Mapper Service Controller 前端代码 四、测试 一、需求及界面展示 需求: 1. 输入留言信息,点击提交&…

2024-6-遥远的救世主

2024-6-遥远的救世主 2024-4-18 豆豆 fatux: 2021.5.26 看完电视剧《天道》之后购买本书,断断续续一直没有读完。 非常好奇,一个什么样的作者能写出如此奇书。老丁,一个智者,智者是多么孤独,因为找不到同…

AtCoder Regular Contest 178 A~D

A.Good Permutation 2(贪心) 题意: 给你一个正整数 N N N和一个由 M M M个正整数 A ( A 1 , A 2 , … , A M ) A(A_{1},A_{2}, \dots,A_{M}) A(A1​,A2​,…,AM​)组成的序列。 在这里, A A A的所有元素都是介于 1 1 1和 N N …

nss做题

[NCTF 2018]签到题 1.f12在index.php中找到flag [NSSCTF 2022 Spring Recruit]ezgame 1.在js源码中就有flag [UUCTF 2022 新生赛]websign 1.打开环境后发现ctrlu和右键,f12都被禁用了。两种方法,第一种:禁用js;第二中提前打开…

数据结构(五)树与二叉树

2024年5月26日一稿(王道P142) 基本概念 术语 性质 二叉树 5.2.2 二叉树存储结构

vue3中基于element-plus封装一个表格弹框组件,要求可以单选和多选table数据

单选&#xff1a; <template><SelectMaterialref"selectMaterialRef"check"checkbox"select"selectMaterial"></SelectMaterial><el-button type"primary" size"small" icon"el-icon-plus"…

【STM32】新建工程(江科大)

文章目录 STM32的开发方式库函数文件夹一、新建一个基于标准库的工程1.建立一个存放工程的文件夹2.打开Keil5 二、通过配置寄存器来完成点灯1.配置RCC寄存器2.配置PC13口&#xff08;1&#xff09;配置PC13口的模式&#xff08;2&#xff09;给PC13口输出数据 三、为寄存器添加…

与MySQL的初相遇

&#x1f30e;初识MySQL 注&#xff1a;本文SQL语句只为了验证猜想&#xff0c;不会也不要紧。 文章目录&#xff1a; MySql开端 认识数据库       什么是数据库       主流数据库       MySQL的本质 MySQL基础使用       连接mysql服务器     …

【Linux初探】:解锁开源世界的神秘钥匙

文章目录 &#x1f680;一、了解Linux&#x1f525;二、Linux 的发行版❤️三、Linux应用领域&#x1f4a5;四、Linux vs Windows & mac &#x1f680;一、了解Linux Linux是一种自由、开放源代码的操作系统&#xff0c;它的内核由芬兰计算机科学家Linus Torvalds在1991年创…

图片AI高效生成惊艳之作,一键解锁无限创意,轻松打造概念艺术新纪元!

在数字化时代&#xff0c;图片已经成为我们表达创意、传递信息的重要载体。然而&#xff0c;传统的图片生成方式往往耗时耗力&#xff0c;无法满足我们对于高效、创意的需求。幸运的是&#xff0c;现在有了图片AI&#xff0c;它以其高效、智能的特点&#xff0c;为我们带来了全…

数组-最接近给出数字的三数之和

题目描述 解题思路 这里使用三层for循环&#xff0c;暴力解法穷举所有三个数和的可能性&#xff0c;注意三层循环里的索引不要重复。 代码实现 import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返…

C语言——小知识和小细节19

一、奇数位与偶数位互换 1、题目介绍 实现一个宏&#xff0c;将一个整数的二进制补码的奇数位与偶数位互换。输出格式依旧是十进制整数。示例&#xff1a; 2、分析 既然想要交换奇数位和偶数位上的数字&#xff0c;那么我们就要先得到奇数位和偶数位上的数字&#xff0c;那么…

THREE.JS中的向量点乘,以及他的几何意义。

1. THREE.JS中的向量点乘&#xff0c;以及他的几何意义 向量点乘的公式 : 2. 在three.js 中计算向量点乘 const a new THREE.Vector3(10, 10, 0); const b new THREE.Vector3(20, 0, 0); const dot a.dot(b);从这里可以看出&#xff0c;向量的点乘的结果是一个数字(标量…

嵌入式进阶——LED呼吸灯(PWM)

&#x1f3ac; 秋野酱&#xff1a;《个人主页》 &#x1f525; 个人专栏:《Java专栏》《Python专栏》 ⛺️心若有所向往,何惧道阻且长 文章目录 PWM基础概念STC8H芯片PWMA应用PWM配置详解占空比 PWM基础概念 PWM全称是脉宽调制&#xff08;Pulse Width Modulation&#xff09…

安卓手机电脑平板均支持

最近随着人工智能的火热&#xff0c;越来越多人问我怎么设置&#xff0c;我这边主要提供简单的配置&#xff0c;能够实现想要的功能&#xff0c;不懂得的友友们可以私聊我&#xff0c;