保健励志美文体育育儿作文
投稿投诉
作文动态
热点娱乐
育儿情感
教程科技
体育养生
教案探索
美文旅游
财经日志
励志范文
论文时尚
保健游戏
护肤业界

对不起,我错了,这代码不好写

  hello,大家好呀,我是小楼。
  前几天不是写了这篇文章《发现一个开源项目优化点,点进来就是你的了》嘛。
  文章介绍了Sentinl的自适应缓存时间戳算法,从原理到实现都手把手解读了,而且还发现SentinelGo还未实现这个自适应算法,于是我就觉得,这简单啊,把Java代码翻译成Go不就可以混个PR?
  甚至在文章初稿中把这个描述为:有手就可以,感觉不太妥当,后来被我删掉了。
  过了几天,我想去看看有没有人看了我的文章真的去提了个PR,发现仍然是没有,心想,可能是大家太忙(懒)了吧。
  于是准备自己来实现一遍,周末我拿出电脑试着写一下这段代码,结果被当头一棒敲醒,原来这代码不好写啊。
  如何实现
  先简单介绍一下我当时是如何实现的。
  首先,定义了系统的四种状态:const(UNINITIALIZEDiotaIDLEPREPARERUNNING)
  这里为了让代码更加贴近Go的习惯,用了iota。
  用了4种状态,第一个状态UNINITIALIZED是Java版里没有的,因为Java在系统初始化时默认就启动了定时缓存时间戳线程。
  但Go版本不是这样的,它有个开关,当开关开启时,会调用StartTimeTicker来启动缓存时间戳的协程,所以当没有初始化时是需要直接返回系统时间戳,所以这里多了一个UNINITIALIZED状态。
  然后我们需要能够统计QPS的方法,这块直接抄Java的实现,由于不是重点,但又怕你不理解,所以直接贴一点代码,不想看可以往下划。
  定义我们需要的BucketWrap:typestatisticstruct{readsuint64writesuint64}func(sstatistic)NewEmptyBucket()interface{}{returnstatistic{reads:0,writes:0,}}func(sstatistic)ResetBucketTo(bucketbase。BucketWrap,startTimeuint64)base。BucketWrap{atomic。StoreUint64(bucket。BucketStart,startTime)bucket。Value。Store(statistic{reads:0,writes:0,})returnbucket}
  获取当前的Bucket:funccurrentCounter(nowuint64)(statistic,error){ifstatisticsnil{returnnil,fmt。Errorf(statisticsisnil)}bk,err:statistics。CurrentBucketOfTime(now,bucketGenerator)iferr!nil{returnnil,err}ifbknil{returnnil,fmt。Errorf(currentbucketisnil)}v:bk。Value。Load()ifvnil{returnnil,fmt。Errorf(currentbucketvalueisnil)}counter,ok:v。(statistic)if!ok{returnnil,fmt。Errorf(bucketfailtodotypeassert,expect:statistic,infact:s,reflect。TypeOf(v)。Name())}returncounter,nil}
  获取当前的QPS:funccurrentQps(nowuint64)(uint64,uint64){ifstatisticsnil{return0,0}list:statistics。ValuesConditional(now,func(wsuint64)bool{returnwsnownowwsuint64(bucketLengthInMs)})varreads,writes,cntuint64for,w:rangelist{ifwnil{continue}v:w。Value。Load()ifvnil{continue}s,ok:v。(statistic)if!ok{continue}cntreadss。readswritess。writes}ifcnt1{return0,0}returnreadscnt,writescnt}
  当我们有了这些准备后,来写核心的check逻辑:funccheck(){now:CurrentTimeMillsWithTicker(true)ifnowlastCheckcheckInterval{return}lastChecknowqps,tps:currentQps(now)ifstateIDLEqpshitsUpperBoundary{logging。Warn(〔timetickercheck〕switchestoPREPAREforbetterperformance,reads,qps,writes,tps)statePREPARE}elseifstateRUNNINGqpshitsLowerBoundary{logging。Warn(〔timetickercheck〕switchestoIDLEduetonotenoughload,reads,qps,writes,tps)stateIDLE}}
  最后是调用check的地方:funcStartTimeTicker(){varerrerrorstatistics,errbase。NewLeapArray(sampleCount,intervalInMs,bucketGenerator)iferr!nil{logging。Warn(〔timetickerStartTimeTicker〕newleaparrayfailed,error,err。Error())}atomic。StoreUint64(nowInMs,uint64(time。Now()。UnixNano())unixTimeUnitOffset)stateIDLEgofunc(){for{check()ifstateRUNNING{now:uint64(time。Now()。UnixNano())unixTimeUnitOffsetatomic。StoreUint64(nowInMs,now)counter,err:currentCounter(now)iferr!nilcounter!nil{atomic。AddUint64(counter。writes,1)}time。Sleep(time。Millisecond)continue}ifstateIDLE{time。Sleep(300time。Millisecond)continue}ifstatePREPARE{now:uint64(time。Now()。UnixNano())unixTimeUnitOffsetatomic。StoreUint64(nowInMs,now)stateRUNNINGcontinue}}}()}
  自此,我们就实(抄)现(完)了自适应的缓存时间戳算法。测试一下
  先编译一下,咚,报错了:importcyclenotallowed!
  啥意思呢?循环依赖了!
  我们的时间戳获取方法在包util中,然后我们使用的统计QPS相关的实现在base包中,util包依赖了base包,这个很好理解,反之,base包也依赖了util包,base包主要也使用了CurrentTimeMillis方法来获取当前时间戳,我这里截个图,但不止这些,有好几个地方都使用到了:
  但我写代码时是特地绕开了循环依赖,也就是util中调用base包中的方法是不会反向依赖回来形成环的,为此还单独写了个方法:
  使用新方法,就不会形成依赖环。但实际上编译还是通过不了,这是因为Go在编译时就直接禁止了循环依赖。
  那我就好奇了啊,Java是怎么实现的?
  这是com。alibaba。csp。sentinel。util包
  这是com。alibaba。csp。sentinel。slots。statistic。base包
  Java也出现了循环依赖,但它没事!
  这瞬间勾起了我的兴趣,如果我让它运行时形成依赖环,会怎么样呢?
  简单做个测试,搞两个包,互相调用,比如pk1和pk2的code方法都调用对方:packageorg。newboo。pk1;importorg。newboo。pk2。Test2;publicclassTest1{publicstaticintcode(){returnTest2。code();}publicstaticvoidmain(String〔〕args){System。out。println(code());}}
  编译可以通过,但运行报错栈溢出了:Exceptioninthreadmainjava。lang。StackOverflowErroratorg。newboo。pk1。Test1。code(Test1。java:7)atorg。newboo。pk2。Test2。code(Test2。java:7)。。。
  这么看来是Go编译器做了校验,强制不允许循环依赖。
  说到这里,其实Java里也有循环依赖校验,比如:Maven不允许循环依赖,比如我在sentinelcore模块中依赖sentinelbenchmark,编译时就直接报错。
  再比如SpringBoot2。6。x默认禁用循环依赖,如果想用,还得手动打开才行。
  Java中强制禁止的只有maven,语言层面、框架层面基本都没有赶尽杀绝,但Go却在语言层面强制不让使用。
  这让我想起了之前在写Go代码时,Go的锁不允许重入,经常写出死锁代码。这搁Java上一点问题都没有,当时我就没想通,为啥Go不支持锁的重入。
  现在看来可能的原因:一是Go的设计者有代码洁癖,想强制约束大家都有良好的代码风格;二是由于Go有循环依赖的强制检测,导致锁重入的概率变小。
  但这终究是理想状态,往往在实施起来的时候令人痛苦。
  反观Java,一开始没有强制禁用循环依赖,导致后面基本不可避免地写出循环依赖的代码,SpringBoot认为这是不好的,但又不能强制,只能默认禁止,但如果你真的需要,也还是可以打开的。
  但话又说回来,循环依赖真的丑陋吗?我看不一定,仁者见仁,智者见智。如何解决
  问题是这么个问题,可能大家都有不同的观点,或是吐槽Go,或是批判Java,这都不是重点,重点是我们还得在Go的规则下解决问题。
  如何解决Go的循环依赖问题呢?稍微查了一下资料,大概有这么几种方法:方法一
  将两个包合成一个,这是最简单的方法,但这里肯定不行,合成一个这个PR铁定过不了。方法二
  抽取公共底层方法,双方都依赖这个底层方法。比如这里,我们把底层方法抽出来作为common,util和base同时依赖它,这样util和base就不互相依赖了。utilcommonbasecommon
  这个方法也是最常见,最正规的方法。
  但在这里,似乎也不好操作。因为获取时间戳这个方法已经非常底层了,没办法抽出一个和统计QPS共用的方法,反正我是没能想出来,如果有读者朋友可以做到,欢迎私聊我,真心求教。
  花了很多时间,还是没能搞定。当时的感觉是,这下翻车了,这题可没那么简单啊!方法三
  这个方法比较难想到,我也是在前两个方法怎么都搞不定的情况下咨询了组里的Go大佬才知道。
  仔细看获取时间戳的代码:ReturnsthecurrentUnixtimestampinmilliseconds。funcCurrentTimeMillis()uint64{returnCurrentClock()。CurrentTimeMillis()}
  这里的CurrentClock()是什么?其实是返回了一个Clock接口的实现typeClockinterface{Now()time。TimeSleep(dtime。Duration)CurrentTimeMillis()uint64CurrentTimeNano()uint64}
  作者这么写的目的是为了在测试的时候,可以灵活地替换真实实现
  实际使用时RealClock,也就是调用了我们正在调优的时间戳获取;MockClock则是测试时使用的。
  这个实现是什么时候注入的呢?funcinit(){realClock:NewRealClock()currentClocknew(atomic。Value)SetClock(realClock)realTickerCreator:NewRealTickerCreator()currentTickerCreatornew(atomic。Value)SetTickerCreator(realTickerCreator)}
  在util初始化时,就写死注入了realClock。
  这么一细说,是不是对循环依赖的解决有点眉目了?
  我们的realClock实际上依赖了base,但这个realClock可以放在util包外,util包内只留一个接口。
  注入真实的realClock的地方也不能放在util的初始化中,也得放在util包外(比如Sentinel初始化的地方),这样一来,util就不再直接依赖base了。
  这样一改造,编译就能通过了,当然这代码只是个示意,还需要精雕细琢。最后
  我们发现就算给你现成的代码,抄起来也是比较难的,有点类似脑子会了,但手不会的尴尬境地。
  同时每个编程语言都有自己的风格,也就是我们通常说的,Go代码要写得更Go一点,所以语言不止是一个工具这么简单,它的背后也存在着自己的思考方式。
  本文其实是从一个案例分享了如何解决Go的循环依赖问题,以及一些和Java对比的思考,更偏向代码工程。
  如果你觉得还不过瘾,也可以看看这篇文章,也是关于代码工程的:《惨,给Go提的代码被批麻了》
  看完,记得点个关注、赞、在看哦,这样我才有动力持续输出优质技术文章我们下期再见吧。
  搜索关注捉虫大师,后端技术分享,架构设计、性能优化、源码阅读、问题排查、踩坑实践。

守护甜心之殇蝶自从亚梦升入初一压力自然就多了起来。夏天又来到了,亚梦渐渐地养成了一个习惯,听歌mdash;mdash;MP3从不离手。关于听的嘛就是歌呗的歌曲。以前那几首已经听得可以背……成长的路上感谢有你导语:小草应感谢雨露,给以她滋润;小鸟应感谢蓝天,给她飞翔的空间;小鱼应感谢大海,给她嬉戏的乐园。小编整理成长的路上感谢有你,欢迎阅读。第一篇:成长的路上感谢有你当……为什么有些人一辈子抽烟喝酒,还能活到90岁以上?吃饭要喝二两酒,饭后来上一根烟,这个状态简直就是现在大部分中年人的真实写照。其实小编的爸爸以前每天也都要喝上几两白酒的,除了早上不喝,基本每天中午、晚上都要喝一点,自从做了心脏……一样的夏天透过手心指缝间眯着眼睛看夏日里的阳光,有一点眩晕,凝视那轮满是沧桑的太阳。又是一年的夏天。夏日的阳光是不是有很大的穿透力,不然为什么总能将我冰封的心灵打动,溶解helli……家里有学生,早餐就这样给她做,5分钟搞定,营养全面,孩子爱吃老话说一日之计在于晨,同样在饮食上,早餐是显得非常重要的。经过了几个小时的睡眠,身体的营养已经吸收一空,早餐就要好好地补充营养,这样一天的学习工作都可以元气满满。尤其是家……宝女郎张俪被称渣男回收站,36岁仍未婚,成名路上有眼泪要说《浪姐3》一公的封神舞台,很多人都投给了《野蔷薇》。舞台很炸,张俪美得很显眼。长发大波浪、亮片裙红手套,妆容笑容都很自然,在舞台上超有魅力。不得提一下,在……人生的风景作文500字老师告诉我们地生会考日期的时候,说到时间过的迅速,那一刻,我突然意识到,时间随着我们的长大流逝的越来越快,快到再也抓不住,只留下一个背影,在人生的轨迹中,慢慢蹒跚。也突然想了很……人教版高中第五册二单元作文那年的月吊影分为千里雁,辞根散作九秋蓬。共看明月应垂泪,一夜乡心五处同。题记月是别在苍穹上的一枚相思玉。中秋本是最思念的,而今却变得最伤感的。月好像依旧是当年的月,人却不是……出汗是为身体在排毒吗?出汗位置不同,或说明不同的问题,应注意出汗是人体的正常生理表现,尤其是外界温度高于人体表面温度时,我们会通过排汗的方式来进行散热生活当中也有一些人爱出汗,有些人不爱出汗,那么出汗会不会是在为身体排毒呢?汗液的……初中一年级作文军训心得三天的时光,看似短暂却又无比漫长。三天军训,有疲惫,有兴奋,有依恋,有不舍三天时间不长,却给我们上了重要的一课!当大家小心翼翼的穿上军装,有兴奋,有激动。教官说:穿上军装……陶行知生活教育学说读后感作文读完《陶行知生活教育学说》,陶行知先生许多独特的教育观点与开拓性地教育实践便深深地印刻在我的内心,他让我看到了教育更为广阔与深远的内涵,他也让我有了太多值得思考与借鉴的实践范例……吃10斤大豆不如1斤它!越吃心脏越舒服,6月要多吃几次有这么一种食物,它翠绿圆滑,口感清爽,食后齿颊留香。它貌不惊人,但营养丰富,还会让你越吃越快乐!吃豌豆的8个理由豌豆是一年生攀援草本植物,李时珍在《本草纲目》……
新手必知!30个护肤小知识!看完护肤不踩雷如何养成干净的脸?敏感肌可以防晒吗?如何变白?这些护肤小知识你知道吗?为了有一身走出去人人羡慕的好皮肤,喵姐整理了一些生活中让皮肤变好的小习惯,和大家分享1、……家乡的油菜花小学600字作文春天来了,家乡的田野里最迷人的就数那婀娜多姿、色彩明丽的油菜花了!站在至高点狮子山上,一大片一大片的金黄逼入你眼帘,绵延数里。下面是关于家乡的油菜花小学600字作文的内容,欢迎……如果一颗恒星的半径是太阳的10倍,那么它有多大?离地球最近的恒星是我们熟知的太阳,可能在我们的印象中它是非常巨大的,但是你知道它到底有多么庞大吗?也许你没有直观的感受,那我们来看看它的数据是多少,太阳的直径是地球的109倍,……将一颗恒星从它的位置移开中国太空望远镜将如何搜索地球2。0一个新的轨道望远镜将有助于在类似于太阳的恒星周围寻找宜居行星。来自中国的科学家提出了一个空间天文台项目,该项目使用一种不寻常但有效的方式来寻找类地世界。艺术家对类地行星的……勇士队注意到,在第三场热身时,TD花园的篮筐太高花园工作人员用梯子测量了两个环,果然是勇士的环高了几英尺金州勇士队抵达TD花园观看NBA总决赛第三场比赛,发现他们在热身赛中投篮的篮筐高度不对。一根10英尺长的木杆……一财城市榜惹争议,新一线我为何选蓉汉杭宁?6月1日,伴随着中国最大城市的全面复工、复产、复市,一年一度的《2022城市商业魅力排行榜》也如期而至。这份由第一财经新一线城市研究所发布的榜单,采用了170个主流消费品……吉利汽车5月销量出炉以全优成绩领跑,新能源再创新高近日,吉利汽车2022年5月销量数据出炉:5月共计销售89070辆,环比增长23。5,位居行业第三。其中,吉利品牌销售60404辆,环比增长22;几何品牌销售8967辆,……国内外要闻每日一览每天5分钟,了解汽车新资讯国内新闻1。财政部:持续完善新能源汽车购置补贴政策2。福建:加大汽车消费每辆补贴3000元以上3。深圳:到2025年全市新能源……通知!这三地公积金可跨界租房记者6月8日获悉,为进一步提升区域一体化发展服务水平,服务长三角区域内人才流动、产业发展,支持职工租房需求,长三角生态绿色一体化发展示范区日前出台相关通知,支持职工提取住房公积……失控全人类的最终命运读后感小学生作文500字这一本书涉及了多方面的内容,机器、系统、生物以及社会等。在过去的十年里,这是世界公认最具有智慧和价值的一本书。放在现在来看,这本书还是写得很好的。在此,我不得不佩服作者凯文凯利……眼睛干涩,视物模糊?妙用两个中药,一清一补,有效缓解视疲劳大家好,我是沈医生。有些人经常会感到眼睛干涩、视物疲劳、风一吹就会流泪,有时候还觉得眼里有东西,想用手去揉,甚至出现了看东西模糊的情况,这多见就是得了干眼症了。滴用人工泪液后只……拒绝7000万大合同的小托马斯一共赚到多少钱?他后悔都来不及小托马斯是一位非常励志的球员,他的身高只有1米75,在长人如林的NBA就是个小矮人,他却拥有巨人一样的能量。他在2011年参加NBA选秀,在第60顺位才被国王队选中,他没有因此……
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网