首页 > 其他分享 >Golang基础-mutex的正常模式和饥饿模式1

Golang基础-mutex的正常模式和饥饿模式1

时间:2025-01-07 14:34:23浏览次数:3  
标签:goroutine 模式 Golang 饥饿 Mutex Go mutex 等待

正常模式(非公平锁)

正常模式下,所有等待锁的goroutine按照FIFO(先进先出)顺序等待。唤醒的goroutine不会直接拥有锁,而是会和新请求goroutine竞争锁。新请求的goroutine更容易抢占:因为它正在CPU上执行,所以刚刚唤醒goroutine有很大可能在锁竞争中失败。在这种情况下,这个被唤醒的goroutine会加入到等待队列的前面。

饥饿模式(公平锁)

为了解决了等待goroutine队列的长尾问题饥饿模式下,直接由unlock把锁交给等待队列中排在第一位的goroutine (队头),同时,饥饿模式下,新进来的goroutine不会参与抢锁也不会进入自旋状态,会直接进入等待队列的尾部。这样很好的解决了老的goroutine一直抢不到锁的场景。饥饿模式的触发条件:当一个goroutine等待锁时间超过1毫秒时,或者当前队列只剩下一个goroutine的时候,Mutex切换到饥饿模式。

这种说法 不完全正确,并且有一些误解。Go 的 sync.Mutex 本身并没有明确的机制来判断锁是否进入饥饿模式,也没有内建的机制来检测一个 goroutine 等待锁的时间是否超过某个阈值(如 1 毫秒)。Go 的 Mutex 并不会自动在某些条件下切换到饥饿模式,且也没有在标准库中实现 "饥饿模式" 的自动切换。

Go 中 sync.Mutex 的工作原理

Go 的 sync.Mutex 是一个 非公平 锁,也就是说,Go 的 Mutex 并不会保证按照请求锁的顺序来分配锁。Mutex 的主要目标是保证并发安全,不会有显式的控制来避免饥饿(例如,锁的等待时间超过某个阈值)。

sync.Mutex 的实现中,当一个 goroutine 获取了锁时,其他请求锁的 goroutine 会被阻塞,直到锁被释放为止。当一个 goroutine 释放锁时,操作系统的调度器(而非 Mutex 本身)决定哪个等待的 goroutine 会获取锁。Go 并没有提供内建的公平性机制。

关于饥饿模式

  1. 饥饿模式的触发时机: Go 标准库的 sync.Mutex 并没有实现一个 "饥饿模式" 的自动切换。所谓饥饿模式(Starvation Mode)一般是指某些 goroutine 因为竞争条件或调度策略的原因,永远无法获得锁,导致它们在某些情况下得不到执行。Go 的 Mutex 并不会自动进入饥饿模式,也不会因为某个 goroutine 等待过久而强制切换。

    但是,某些情况可能会导致饥饿

    • 长时间持有锁的 goroutine:如果一个 goroutine 持有锁的时间很长,其他请求锁的 goroutine 可能会长时间等待,导致这些 goroutine 在某些情况下看起来像是进入了饥饿模式。

    • 无限循环的竞争:如果某些 goroutine 一直获取到锁,其他 goroutine 就会一直等待,造成饥饿问题。

    但这种情况完全依赖于程序设计,Go 本身没有内建的机制来控制或检测 "等待锁的时间"。

  2. “只有一个 goroutine 队列”: 当队列中只剩下一个 goroutine 时,锁本身的行为与正常模式类似,因为没有其他竞争者,它会立即获取锁。Go 不会进入饥饿模式,反而是这种情况最为简单,Mutex 就像正常的同步机制一样,顺利执行。

  3. "等待超过 1 毫秒": Go 的 sync.Mutex 并没有内建的机制去追踪一个 goroutine 等待锁的时间是否超过 1 毫秒等阈值,也没有基于时间来决定是否切换锁的行为。如果某个 goroutine 阻塞时间很长,通常是因为某些其他原因,如:

    • 锁的竞争非常激烈。

    • 锁被长时间持有。

    • 操作系统调度的问题。

    Go 的 Mutex 本身没有为这种场景提供专门的机制。

如何避免饥饿模式

如果你担心饥饿模式,可以尝试以下方法来确保公平性:

  1. 公平锁(Fair Mutex): 可以自己实现公平的锁,保证 goroutine 按照请求锁的顺序来获取锁。例如,可以使用 channelsync.Cond 等机制来实现一个公平的锁调度。

  2. 重试机制: 在某些情况下,可以设计重试机制,允许等待过长时间的 goroutine 在没有获取到锁时重新尝试。通过这种方式可以避免长时间等待的情况,减少饥饿现象。

  3. 减少锁粒度: 尽量减少锁持有的时间,避免长时间持有锁而阻塞其他 goroutine。如果可能,可以将锁的粒度降低,将大的临界区分割成多个小的临界区,从而减少竞争。

  4. 优先级队列: 可以使用优先级队列来调度需要锁的 goroutine,以确保某些重要的任务优先获得执行机会。

总结

  • Go 中的 sync.Mutex 没有内建的机制会根据等待时间切换到饥饿模式,也没有内建的时间阈值来判断某个 goroutine 是否等待了过久。

  • Go 的 Mutex 是一个 非公平的锁,即没有保证按照请求锁的顺序进行锁分配,这可能会导致一些 goroutine 长时间无法获得锁,从而出现类似饥饿的问题。

  • 饥饿模式 本身是开发者需要注意的问题,通过合理的锁设计、优先级管理等方式可以减少饥饿现象。

Go 没有内建的机制来监控锁的等待时间或进入饥饿模式,因此开发者需要自己注意并发的公平性。

总结

对于两种模式,正常模式下的性能是最好的,goroutine可以连续多次获取锁,饥饿模式解决了取锁公平的问题,但是性能会下降,这其实是性能和公平的一个平衡模式。

标签:goroutine,模式,Golang,饥饿,Mutex,Go,mutex,等待
From: https://blog.csdn.net/qq_38609643/article/details/144962731

相关文章

  • xxl_job系列---【Glue(java)模式如何通过动态参数传参?】
    1.编辑GLUE(Java)模式的定时任务这里以传递json参数为例:修改任务参数:{"startDate":"","endDate":"","desc":"入参日期格式:yyyyMMdd"}保存。2.编辑此定时任务的GLUE脚本import添加:importcom.xxl.job.core.context.XxlJobHelper;importcn.hutool......
  • javascript如何判断浏览器是否支持严格模式?
    在JavaScript中,严格模式(StrictMode)是一种特殊的执行模式,它可以帮助开发者避免一些常见的错误,并提供更强的错误检查。要在JavaScript中启用严格模式,你需要在脚本或函数的顶部添加"usestrict";声明。然而,直接检测浏览器是否“支持”严格模式并不直接可行,因为严格模式不是浏览器的......
  • javascript设置"严格模式"有什么目的?
    设置JavaScript的“严格模式”有以下几个主要目的:消除JavaScript语法的不合理和不严谨之处:通过启用严格模式,可以帮助开发者避免一些在正常模式下可能被忽略的语法错误或不合理之处,从而使代码更加严谨和可靠。提高代码的安全性:严格模式采用了一些安全措施,例如禁止this关键字......
  • 掌握设计模式--适配器模式
    适配器模式(AdapterPattern)适配器模式是一种结构型设计模式,用于将一种接口转换为客户端期望的另一个接口,使得原本因接口不兼容而无法一起工作的类可以协同工作。适配器为中间者,连接着两个互不相容的接口,从而实现接口的适配。核心思想:在不改变现有代码的情况下,将一个类的接口转换......
  • 解释器模式
    解释器(Interpreter)模式属于行为型模式的一种。解释器模式为特定的语言定义文法(文法就是语法、规则的意思),并提供一个解释器来解析输入的语言(通常是字符串或符号序列)并执行相应的操作。解释器模式适用于需要处理复杂语法的场景,常见于编程语言的解释器、表达式计算器、配置文件解析......
  • 「全网最细 + 实战源码案例」设计模式——外观模式
    概念外观模式是一种结构型模式,为复杂的子系统提供一个统一的接口,使得子系统的功能对外界更加简单、易用。与真实世界的类比当你通过打电话给商店下达订单时,接线员就是该商店所有服务和部门的外观。接线员为你提供了一个包含购物系统、支付网关、送货等服务的简单语言接口......
  • 01背包问题 Golang实现
    背包问题的分类:01背包描述:有n件物品和一个最多能背重量为w的背包。第i件物品的重量是weight[i],得到的价值是value[i]。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。思路分析:问题核心:从给定的......
  • 96. 不同的二叉搜索树 && 343. 整数拆分 Golang实现
    这两个题目的分析思路是十分类似的。都是进行一个拆分。1.不同的二叉搜索树题目描述:给你一个整数n,求恰由n个节点组成且节点值从1到n互不相同的二叉搜索树有多少种?返回满足题意的二叉搜索树的种数。示例1:输入:n=3输出:5思路分析:动态规划分析:确定状态:令dp[i]......
  • 掌握设计模式--抽象工厂模式
    抽象工厂模式(AbstractFactoryPattern)抽象工厂模式是一种创建型设计模式,它提供了一个接口,用于创建一组相关或依赖的对象,而无需指定具体类。它涉及到多个工厂,每个工厂负责创建一类相关产品的对象,确保客户端在不需要了解具体类的情况下,能够通过抽象工厂来获得所需的一系列产品。......
  • 【C++ 设计模式】C++ 设计模式全景剖析:从语言特性到工程落地
    目录标题第一章:设计模式与C++:初识与动机1.1为什么要学习设计模式1.1.1面向扩展与维护的必然需求1.1.2提升沟通效率与团队协作1.2C++设计模式的核心特征1.2.1灵活运用RAII与多态1.2.2编译期与运行期并行的优势1.3学习与使用设计模式的关键心态1.3.1不为模......