中山网站建设招聘网络营销工具包括

pingmian/2026/1/20 14:59:10/文章来源:
中山网站建设招聘,网络营销工具包括,拍摄企业宣传片公司哪家好,嘉兴网站建设技术托管造个可重入锁的轮子 介绍目标 正文sync.Mutexsync.Mutex介绍多协程计数器demo多协程计数器加锁 源码剖析Mutex数据结构Lock()加锁核心逻辑 UnLock() 重入锁与可重入锁魔改 sync.Mutex 参考文档 介绍 开新坑啦#xff01;#xff01; 从这篇文章开始#xff0c;尝试造轮子 从这篇文章开始尝试造轮子包括一些可能有用、也可能没用的轮子。 温故而知新我相信时常回顾基础的东西能让我们受益良多这点我深有体会每过一段时间我都会把《程序员的自我修养》拿出来翻翻常翻常新每次读都能有新的收获开始吧。 “转向毕竟是一个很长的过程先做起来吧给我和别的生命一个活下去的机会。”—《三体》 目标 用go 实现可重入锁 正文 Golang的sync.Mutex是并发场景下的“灵丹妙药”但是我们真的了解吗 本文通过对源码的剖析让我们重新、更全面的认识sync.Mutex尤其是其优缺点。 在对sync.Mutex有了深入了解后我们尝试对其进行魔改实现可重入锁。 sync.Mutex 点击上方的sync.Mutex进入golang.tour我们可以看到sync.Mutex的简单介绍 总结如下 sync.Mutex介绍 当多个goroutine之间需要通信尤其需要访问同一份数据时需要互斥锁来保证一次只有一个goroutine访问数据。 当然sync.Mutex作为一个同步原语实现了Locker接口后面会提到所以只有Lock()、Unlock()两个接口。 多协程计数器demo 比如大家在许多地方看到的例子多协程累加计数 var (counter 1 )func incrCounter() {var wg sync.WaitGroupwg.Add(11)i : 0for {go func() {defer wg.Done()iter:0for {counter if iter 4 {break}iter }}()if i 9 {break}i }wg.Wait()fmt.Println(incrCounter:,counter)os.Exit(1) } 本地运行结果是incrCounter: 56大家可以试试本地运行的结果。 多协程计数器加锁 接下来就说到今天的主角了在上面的多协程计数器代码上集成sync.Mutex加两行代码分别是Lock、Unlock 代码如下 var (mtx sync.Mutexcounter 1 ) func incrCounter() {var wg sync.WaitGroupwg.Add(11)i : 0for {go func() {defer wg.Done()iter:0for {mtx.Lock() counter mtx.Unlock()if iter 4 {break}iter }}()if i 9 {break}i }wg.Wait()fmt.Println(incrCounter:,counter)os.Exit(1) } 本地运行结果是incrCounter: 67大家可以试试本地运行的结果。(相信很多人看到67会觉得奇怪没错我是故意的就是给粗心的同学卖了一个坑想想为什么是67而不是66) 奇怪哎为啥加了sync.Mutex不一样了呢 这里一定要回顾下开头sync.Mutex的介绍 源码剖析 点击sync.Mutex,我们可以看到它的数据结构 Mutex数据结构 简单解释下分别是 state状态位如果不是远古版本分为了4段以及sema信号量变量不急后面会细说这里先了解基本构成 type Mutex struct {state int32sema uint32 }回顾多协程计数器中sync.Mutex的使用例子核心方法只有两个为什么只有两个呢看源码发现原来是实现了Locker interface因为实现了Locker所以有Lock()、UnLock() 这里需要重点说一下golang中的同步原语都会实现Locker 比如RWMutex所以以后提到Lock、UnLock那么就可以思考是不是实现了Locker interface // A Locker represents an object that can be locked and unlocked. type Locker interface {Lock()Unlock() }接下来看下Lock()的实现看看golang是如何加锁的。 Lock() 照例点进去看下源码 如果没加锁运气很好加锁就行然后返回如果已经加过锁了那么就进入lockSlow也是加锁逻辑最复杂的地方 race是做死锁检查的先不管捋主体逻辑先 这里多提一下fast path一般用来表示捷径或者幸运case意思是直接成功不用再执行复杂的逻辑如果大家看多了开源项目看到fast path就可以跳过这段代码因为不用看你也能猜到这段代码的意思 func (m *Mutex) Lock() {// Fast path: grab unlocked mutex.if atomic.CompareAndSwapInt32(m.state, 0, mutexLocked) {if race.Enabled {race.Acquire(unsafe.Pointer(m))}return}// Slow path (outlined so that the fast path can be inlined)m.lockSlow() }加锁核心逻辑 先看几个变量 表示饥饿模式的starving 唤醒状态的标记awoke 迭代次数统计的iter 当前的加锁状态old var waitStartTime int64starving : falseawoke : falseiter : 0old : m.state接下来是饥饿模式的自旋逻辑 if old(mutexLocked|mutexStarving) mutexLocked runtime_canSpin(iter) {// Active spinning makes sense.// Try to set mutexWoken flag to inform Unlock// to not wake other blocked goroutines.if !awoke oldmutexWoken 0 oldmutexWaiterShift ! 0 atomic.CompareAndSwapInt32(m.state, old, old|mutexWoken) {awoke true}runtime_doSpin()iterold m.statecontinue}如果是饥饿模式那么直接拿到锁新到的goroutine会放入等待队列等待队列数1 new : old if oldmutexStarving 0 {new | mutexLocked} if old(mutexLocked|mutexStarving) ! 0 {new 1 mutexWaiterShift}如果当前协程是饥饿模式并且Mutex并没有标记为饥饿模式那么就把Mutex标记为饥饿模式如果已被唤醒那么就标记为已唤醒状态 if starving oldmutexLocked ! 0 {new | mutexStarving} if awoke {// The goroutine has been woken from sleep,// so we need to reset the flag in either case.if newmutexWoken 0 {throw(sync: inconsistent mutex state)}new ^ mutexWoken}紧接着将改变的状态同步到Mutex.state字段 如果到目前为止当前协程没有获取到锁也没有进入饥饿模式就可以提前结束当前流程等待下一次唤醒 判断运行时间并调用runtime_SemacquireMutex休眠并尝试获取信号量 运行时间超过1ms就自动进入饥饿模式starving 1 一旦当前Mutex被标记为饥饿模式将状态保存到Mutex.state中 这里需要注意stateint32中各段的 第一段最左边29位为等待协程的数量 第二段1位饥饿模式标记 第三段1位唤醒标记 第四段1位是否加锁 如果没有进入饥饿模式那么将唤醒标记为true并且重新开始继续尝试获取锁 if atomic.CompareAndSwapInt32(m.state, old, new) {if old(mutexLocked|mutexStarving) 0 {break // locked the mutex with CAS}// If we were already waiting before, queue at the front of the queue.queueLifo : waitStartTime ! 0if waitStartTime 0 {waitStartTime runtime_nanotime()}runtime_SemacquireMutex(m.sema, queueLifo, 1)starving starving || runtime_nanotime()-waitStartTime starvationThresholdNsold m.stateif oldmutexStarving ! 0 {// If this goroutine was woken and mutex is in starvation mode,// ownership was handed off to us but mutex is in somewhat// inconsistent state: mutexLocked is not set and we are still// accounted as waiter. Fix that.if old(mutexLocked|mutexWoken) ! 0 || oldmutexWaiterShift 0 {throw(sync: inconsistent mutex state)}delta : int32(mutexLocked - 1mutexWaiterShift)if !starving || oldmutexWaiterShift 1 {// Exit starvation mode.// Critical to do it here and consider wait time.// Starvation mode is so inefficient, that two goroutines// can go lock-step infinitely once they switch mutex// to starvation mode.delta - mutexStarving}atomic.AddInt32(m.state, delta)break}awoke trueiter 0} else {old m.state}UnLock() 记得前面的fast path这个case吗如果state为1就直接释放锁然后就结束了 这里需要结合加锁逻辑去看 回顾下组成state的四个部分 第一段最左边29位为等待协程的数量 第二段1位饥饿模式标记 第三段1位唤醒标记 第四段1位是否加锁 那么state为说明没有等待的协程没有饥饿模式和唤醒标记仅仅Mutex被加锁了 func (m *Mutex) Unlock() {if race.Enabled {_ m.staterace.Release(unsafe.Pointer(m))}// Fast path: drop lock bit.new : atomic.AddInt32(m.state, -mutexLocked)if new ! 0 {// Outlined slow path to allow inlining the fast path.// To hide unlockSlow during tracing we skip one extra frame when tracing GoUnblock.m.unlockSlow(new)} } 否则进入unlockSlow逻辑 入口时异常判断如果释放一个没有加锁的锁则抛出异常 如果是饥饿模式将锁直接给饥饿模式的协程注意是饥饿模式的协程不是等待队列中的等待协程 不是饥饿模式比如正常的等待协程是正常模式判断锁是否已被锁定或者是否存在唤醒或者是否是饥饿模式则直接放回并不释放锁否则唤醒等待队列中的协程直接移交给等待者 func (m *Mutex) unlockSlow(new int32) {if (newmutexLocked)mutexLocked 0 {fatal(sync: unlock of unlocked mutex)}if newmutexStarving 0 {old : newfor {// If there are no waiters or a goroutine has already// been woken or grabbed the lock, no need to wake anyone.// In starvation mode ownership is directly handed off from unlocking// goroutine to the next waiter. We are not part of this chain,// since we did not observe mutexStarving when we unlocked the mutex above.// So get off the way.if oldmutexWaiterShift 0 || old(mutexLocked|mutexWoken|mutexStarving) ! 0 {return}// Grab the right to wake someone.new (old - 1mutexWaiterShift) | mutexWokenif atomic.CompareAndSwapInt32(m.state, old, new) {runtime_Semrelease(m.sema, false, 1)return}old m.state}} else {// Starving mode: handoff mutex ownership to the next waiter, and yield// our time slice so that the next waiter can start to run immediately.// Note: mutexLocked is not set, the waiter will set it after wakeup.// But mutex is still considered locked if mutexStarving is set,// so new coming goroutines wont acquire it.runtime_Semrelease(m.sema, true, 1)} } 重入锁与可重入锁 未完待续 魔改 sync.Mutex 未完待续 参考文档 认识可重入锁 Mutex 饥饿模式

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

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

相关文章

罗湖网站制作费用营销型网站建设策划案

文章目录 载具Vehicle Variety Pack(车辆品种包)Vehicle Variety Pack Volume 2(车辆品种包第 2 卷)家具Free Furniture Pack(免费家具包)Old West - VOL 1 - Interior Furniture(旧西部 - 第1卷 - 家具包)Old West VOL.3 - Travel Supplies and Goods(旧西部 - 第3卷…

邯郸做网站服务商做网站月入

一、本文介绍 本文给家大家带来的改进机制是iRMB,其是在论文Rethinking Mobile Block for Efficient Attention-based Models种提出,论文提出了一个新的主干网络EMO(后面我也会教大家如何使用该主干,本文先教大家使用该文中提出的注意力机制…

西樵营销网站制作企业展厅设计公司重庆

目录 一、基础知识1.异或运算xor2.模2算术(1)模2加法和减法(2)模2乘法(3)模2除法 二、CRC循环冗余检测1.背景2.原理3.求R 一、基础知识 1.异或运算xor 异或,顾名思义,只有当两个数…

网站快速建设软件下载西宁吧 百度贴吧

缓存穿透 一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就去后端系统查找(比如DB)。 一些恶意的请求会故意查询不存在的key,请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透…

离退休部门网站建设情况小游戏开发软件

以实战例子讲述JSON三兄弟的后续故事。实战一:发送JSON网络请求作为JSON老大哥的QJsonValue自知对面的大户人家妹子貌美如花,心里已经打起算盘,先下手为强,后下手遭殃。决定显示下自己的家底,想起这件事,老…

安徽做公司网站哪家好建设与管理局网站

技术背景 技术概述 FPGA实现除法运算是一个比较复杂的过程,因为硬件逻辑与软件程序的区别。如果其中一个操作数为常数,可以通过简单的移位与求和操作代替,但用硬件逻辑完成两变量间除法运算会占用较多的资源,电路结构复杂&#xf…

做网站主机电脑布吉做棋牌网站建设哪家公司便宜

Input 测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数&#xff0c;分别是城镇数目N ( < 1000 )和道路数目M&#xff1b;随后的M行对应M条道路&#xff0c;每行给出一对正整数&#xff0c;分别是该条道路直接连通的两个城镇的编号。为简单起见&#xff0c;城镇…

个人网站用什么软件网站开发定制合同

在智慧电表水表的数据采集和存储过程中&#xff0c;时序数据处理成为一个重要的问题。由于电表水表数据具有时间序列的特点&#xff0c;传统的数据库和数据处理方式往往难以满足大规模数据的高速采集、存储和实时分析需求。因此&#xff0c;越来越多的企业开始进行数据架构改造…

网站开发策划书冠县快搜网站建设有限公司

C里默认int型1的二进制表示为&#xff1a; 0000 0000 0000 0000 0000 0000 0000 0001如果左移31位&#xff0c;会得到最小值 1<<31 //会得到-2147483648&#xff0c;即int型最小值即 1000 0000 0000 0000 0000 0000 0000 0000因为int类型是有符号的&#xff0c;第一位…

无障碍环境建设 网站服装品牌网站开发php

爬虫、数据清洗和分析是在数据科学、数据挖掘和网络爬虫开发领域中常见的概念。 爬虫&#xff08;Web Scraping&#xff09;&#xff1a;爬虫是一种自动化程序或脚本&#xff0c;用于从互联网上的网站上提取信息。这些信息可以是文本、图像、视频或其他类型的数据。爬虫通常会…

PHP网站开发程序员招聘做网站要了解哪些

背景 美团COS&#xff1a;全称美团网核心业务系统部&#xff0c;以持续整合O2O线下资源&#xff0c;共建高效率、低成本的供应链系统&#xff0c;高效推动O2O生态环境建设为业务目标&#xff0c;负责美团网核心业务系统的建设和管理。 COS系统&#xff0c;伴随着美团3年多的发展…

网站建设上市广东新闻联播

02【保姆级】-GO语言开发注意事项&#xff08;特色重点&#xff09; 一、Go语言的特性1.1 第一个hello word&#xff08;详解&#xff09;1.2 开发编译。&#xff08;重要点 / 面试题&#xff09;1.3 开发注意事项1.4 GO语言的转义字符1.5 注释1.6 API 文档 一、Go语言的特性 …

重庆做网站泉州公司辽阳建设网站公司报价

常用的设计模式&#xff1a; 一、单例模式 java中单例模式是一种常见的设计模式&#xff0c;单例模式的写法有好几种&#xff0c;这里主要介绍三种&#xff1a;懒汉式单例、饿汉式单例、双重检查锁定 1、单例模式有以下特点&#xff1a;   a、单例类只能有一个实例。   b…

母婴行业网站建设创建免费网站需要的工具

注解目录 1.制冷设备的监测迫在眉睫 1.1 冷食的利润贡献 1.2 冷设监测系统的困难 &#xff08;制冷设备对于便利店为何如何重要&#xff1f;了解一下你所不知道的便利店和新零售行业。关于电力线载波通信的论战。&#xff09; 2、电路设计 2.1 防护电路 2.1.1 强电防护 …

网站 维护网站建设的整体流程有哪些

由于我之前一直强调数据结构以及算法学习的重要性&#xff0c;所以就有一些读者经常问我&#xff0c;数据结构与算法应该要学习到哪个程度呢&#xff1f;&#xff0c;说实话&#xff0c;这个问题我不知道要怎么回答你&#xff0c;主要取决于你想学习到哪些程度&#xff0c;不过…

电子商务网站建设开发呼市城乡建设厅网站

七、SpringBoot项目的打包与运行 1.目前项目怎么运行的 通过浏览器访问idea 将jar部署到服务器 2.maven 打包项目 命令 mvn package使用命令后会得到如下的jar 3.程序运行 命令 java -jar 项目.jar启动如下 4.springboot打包需要插件 插件 <plugin><group…

撰写网站的建设方案WordPress缺省图

如果想使用其他的qml文件直接创建对象&#xff0c;必须先这样导入其qml文件并as成别名&#xff0c;才可以创建对象并使用它。 一、导入qml文件&#xff0c;例如&#xff1a; import "CameraConfig.qml" as CameraConfig import "CameraDevelopView.qml" a…

做一般的网站要多久wordpress微商城插件

本文 我们来说两个page界面间的数据传递 路由跳转 router.pushUrl 之前我们用了不少了 但是我们只用了它的第一个参数 url 其实他还有个params参数 我们第一个组件可以编写代码如下 import router from ohos.router Entry Component struct Index {build() {Row() {Column() …

网站如何做快捷支付ui设计师是什么意思

为什么80%的码农都做不了架构师&#xff1f;>>> 在编译VC6.0是,出现fatal error C1010: unexpected end of file while looking for precompiled header directive 的错误. 解决方法&#xff1a; 1、如果发生错误的文件是由其他的C代码文件添加进入当前工程而引…

东莞网站设计及拍摄方案公司网站注册理由

linux系统中安装nginx到指定目录 下载要求版本的nginx源码包 上传并解压nginx源码包 # 在/opt/app目录下创建nginx解压安装目录 cd /opt/app mkdir nginx# 切换到解压目录下 cd /opt/app/nginx# 解压 tar -zxvf nginx-1.24.0.tar.gz编译安装 # 在/opt/app/nginx路径下&…