专栏电商日志财经减肥爱情
投稿投诉
爱情常识
搭配分娩
减肥两性
孕期塑形
财经教案
论文美文
日志体育
养生学堂
电商科学
头戴业界
专栏星座
用品音乐

高性能定时器策略之时间轮定时器算法

  时间轮定时器是有多个时间槽(slot)组成,每个时间槽代表时间的基本跨度。类似于一个时钟,时钟指针以恒定的速度每往下走一步,代表一个时间跨度。
  时间槽的个数是固定的,用SN(SlotNum)表示,每转动一次可称为一个滴答(tick),所以转动一周也就需要个SN滴答。每一个滴答需要的槽间间隔为SI(SlotInterval),则转一周也就共需要(SNSI)时间单位。
  时间轮的每个槽都指向一个定时器链表,每个链表的定时器都有一个相同的特性:相差(SNSI)的整数倍,也即是一周的整数倍。正是由于时间轮有这样的特性,所以可以根据定时器的触发时间和时间轮的槽数,把定时器hash到对应的链表上。
  一个简单的时间轮如下图:
  比如我们要插入一个超时时间为TI的定时器,那么计算器应该插入到槽对应的链表的方式如下:
  TS(CS(TISI))SN
  CS代表当前的槽位,因为时间轮定时器不停的在走。
  时间轮采用的是hash的思想,把各个定时器分散到不同槽的链表中,这个避免了单个链表的过长,提高了效率。
  从上面的公式可以看出,对时间轮而言,当SI越小的时候,定时器的精度就越高;当SN槽数越多时,效率越高,因为定时器被分配到不同的链表中,链表的长度也就相对短了,提高了遍历效率。
  下面实现一个简单的时间轮,代码如下:
  includestdio。hincludestdlib。hincludestring。hincludeunistd。hincludesystime。hincludesyssocket。hincludesystypes。hincludesysepoll。hincludeincludetime。hdefineBUFFERSIZE64缓冲区长度defineSLOTSNUM60时间轮上槽的数目结构体声明typedefstructtwtimertwtimer;typedefstructclientdateclientdate;EPOLL回调函数typedefvoid(epollcallbackt)(int,int);structtwtimer{introtation;记录定时器在时间轮上转多少圈后触发inttimeslot;记录定时器属于时间轮上的槽位(对应的链表)void(cbfunc)(clientdate);定时器回调函数clientdateuserdate;client数据twtimerprev;指向前一个定时器twtimernext;指向下一个定时器};用户数据structclientdate{intsockfd;charbuf〔BUFFERSIZE〕;twtimertime;};每1秒时间轮转动一次,也即是槽间隔为1秒staticconstintSI1;时间轮的槽,其中每个元素指向一个定时器链表,链表无序twtimerslots〔SLOTSNUM〕;事件的当前槽intcurslot0;twtimermalloctwtimer(introtation,inttimeslot){twtimertimer(twtimer)malloc(sizeof(twtimer));memset(timer,0,sizeof(twtimer));timerrotationrotation;timertimeslottimeslot;timerprevNULL;timernextNULL;timercbfuncNULL;timeruserdateNULL;returntimer;}voidfreetwtimer(twtimertimer){if(NULLtimer)returnNULL;if(NULL!timeruserdate)free(timeruserdate);free(timer);}voidtimewheel(){inti0;for(i0;iSLOTSNUM;i)slots〔i〕NULL;}遍历每个槽,销毁定时器voiddeltimewheel(){inti0;for(i0;iSLOTSNUM;i){twtimertmpslots〔i〕;while(tmp){slots〔i〕tmpnext;freetwtimer(tmp);tmpslots〔i〕;}}}根据定时器timeout创建一个定时器,并把它插入到一个合适的槽中twtimeraddtimer(inttimeout){if(timeout0)returnNULL;intticks0;待插入的超时时间小于时间轮的槽间隔SI,则将ticks向上调整为1,否则将ticks向下调整为timeoutSIif(timeoutSI){ticks1;}else{tickstimeoutSI;}计算待插入的定时器在时间轮转动多少圈后被触发introtationticksSLOTSNUM;计算待插入的定时器应该被插入到哪个槽中intts(curslot(ticksSLOTSNUM))SLOTSNUM;创建新的定时器,它在时间轮转动rotation圈后被触发twtimertimermalloctwtimer(rotation,ts);若第ts个槽为空,则插入定时器,并将该定时器置为该槽的头结点if(!slots〔ts〕){printf(addtimer,rotationisd,tsisd,curslotisd,rotation,ts,curslot);slots〔ts〕timer;}else否则,将定时器插入其中{printf(slots〔d〕isnotnull,ts);timernextslots〔ts〕;slots〔ts〕prevtimer;slots〔ts〕timer;}returntimer;}voiddeltimer(twtimertimer){if(!timer)return;inttstimertimeslot;slots〔ts〕是目标定时器所在槽头结点,若目标定时器为头结点,则需要重置第ts个槽的头结点if(timerslots〔ts〕){slots〔ts〕slots〔ts〕next;if(slots〔ts〕){slots〔ts〕prevNULL;}}else{timerprevnexttimernext;if(timernext){timernextprevtimerprev;}}freetwtimer(timer);}SI时间到后,调用该函数,时间轮向前滚动一个槽的间隔voidtick(){twtimertmpslots〔curslot〕;遍历该槽对应链表的所有定时器,查看是否触发while(tmp){if(tmprotation0){tmprotation;tmptmpnext;}else到期,执行任务{tmpcbfunc(tmpuserdate);if(tmpslots〔curslot〕){printf(deleteheadincurslot,curslotd,curslot);slots〔curslot〕tmpnext;freetwtimer(tmp);if(slots〔curslot〕)slots〔curslot〕prevNULL;tmpslots〔curslot〕;}else{tmpprevnexttmpnext;if(tmpnext){tmpnextprevtmpprev;}twtimertmp2tmpnext;freetwtimer(tmp);tmptmp2;}}}更新时间轮的当前槽,以反映时间轮的转数curslotcurslotSLOTSNUM;}
  测试如下inttotal0;记录1s定时器触发次数voidtest(clientdatecd){printf(totald,total);}voidtestaddtimer(inttimeout,void(cbfunc)(clientdate)){twtimertimer;timeraddtimer(timeout);timercbfunccbfunc;}voidtestcretetimer(){创建一一个2秒5秒10秒70秒,85秒的定时器testaddtimer(2,test);testaddtimer(5,test);testaddtimer(10,test);testaddtimer(70,test);testaddtimer(85,test);timetnow;structtmtmnow;time(now);tmnowlocaltime(now);printf(testcretetimerdatetime:dddd:d:d,tmnowtmyear1900,tmnowtmmon1,tmnowtmmday,tmnowtmhour,tmnowtmmin,tmnowtmsec);}保存触发定时器相应的fd和回调,在该回调中进行遍历时间轮typedefstructepollcallbackinfo{intiFd;epollcallbacktpfEpollCallBack;}epollcallbackinfo;创建一个触发定时器intcreateTimer(longlMSec,intepfd,epollcallbacktpfEpollCallback){structitimerspecestTimer;structepolleventevent;inttimerfd;intiSec(int)(lMSec1000);intret1;memset(event,0,sizeof(event));event。eventsEPOLLINEPOLLHUPEPOLLERR;memset(stTimer,0,sizeof(stTimer));stTimer。itvalue。tvseciSec;stTimer。itvalue。tvnsec(lMSec1000)1000000;stTimer。itinterval。tvseciSec;stTimer。itinterval。tvnsec(lMSec1000)1000000;timerfdtimerfdcreate(CLOCKMONOTONIC,0);if(1!timerfd){if(0timerfdsettime(timerfd,0,stTimer,NULL)){epollcallbackinfopmalloc(sizeof(epollcallbackinfo));piFdtimerfd;ppfEpollCallbackpfEpollCallback;event。data。ptrp;retepollctl(epfd,EPOLLCTLADD,timerfd,event);}else{printf(timerfdsettimeFailed);}定时器时间设定或添加epoll错误时,释放资源if(0!ret){printf(addtoepollfailedorsettimefailed);close(timerfd);timerfd1;}}else{printf(createtimerfdfailed);}returntimerfd;}voidtimerreadtimerFd(inttimerfd){uint64texp;(void)read(timerfd,exp,sizeof(uint64t));total;return;}epoll上定时器回调,每触发一次则调用一次tick()voidcommomTimerCB(intuiEvent,intiTimeFd){timerreadtimerFd(iTimeFd);tick();}intmain(){structepolleventwaitevent〔100〕;intepfd;inttimerfd;epollcallbacktpfEpllCallback;inti0;structitimerspecestTimer;longlMSec1000;1s定时器时间intcount;epfdepollcreate(1);if(1epfd){printf(epollcreateerror);return1;}printf(createepollfd:d,epfd);timewheel();testcreatetimer();timerfdcreateTimer(lMSec,epfd,(epollcallbackt)commomTimerCB);if(1timerfd){printf(failedtocreatetimer);return1;}for(;;){waitfdsepollwait(epfd,waitevent,100,1);printf(countd,count);for(i0;iwaitfds;i){epollcallbackinfot(epollcallbackinfo)waitevent〔i〕。data。ptr;pfEpllCallback(epollcallbackt)(unsignedlong)tpfEpllCallback;pfEpllCallback(waitevent〔i〕。events,tiFd);}}return0;}

你下载过吗?这些APP被工信部通报!工业和信息化部信息通信管理局今天(2月8日)发布2023年第1批关于侵害用户权益行为的App通报。通报称,依据个人信息保护法网络安全法电信条例电信和互联网用户个人信息保护规定等法律Angew。Chem。Int。Ed。工程化P450BM3用于不饱和烃的直接硝化今天推送的文章是2023年1月发表在AngewandtechemieInternationalEdition上的EngineeringCytochromeP450BM3Enzyme刘强东要建员工福利房?京东31亿元斩获亦庄新城一地块,罕见包含住宅用地2月8日,北京2022年第五批次集中供地第二场结果出炉,至此北京2022年五批次正式落下帷幕,6宗宅地中3宗触顶3宗底价,总收金132。09亿元,成交总面积21。47万,总规划建面采用全新定制OryonCPU内核,高通骁龙8cxGen4曝光2月7日消息,据外媒Notebookcheck报导,高通即将于2024年正式推出基于自研的定制CPU内核Oryon的骁龙处理器,届时将会被命名为骁龙8cxGen4,并将会采用台积电太不要脸!双擎混动敢说电动化丰田你是认真的吗?电池做大再说吧果然玩营销就得不要脸,比如丰田就是这方面的专家。一个油混车型都敢大言不惭的说电动化转型,这让其他新能源企业咋搞?丰田在1月份的销量出来了,南北丰田加一块儿超过了10万台,对比本田和柳岩,被称为宅男女神!一个无数男人心中的人间尤物柳岩,1980年出生,被誉为性感女神,宅男女神柳岩,被说成是借胸上位,一直不温不火,直至画壁中完美的表现,才逐渐红了起来。柳岩一度被认为最性感的女星,而她之前所走的路线也非常具有风青春的调色盘,由我们来执笔来源人民网观点频道青春像是一个调色盘,可以由红黄蓝三原色调出世间所有的色彩。青春没有教科书,每个人都能在这最灿烂的年华绽放出不一样的花朵。青年们可以在三原色的基础上,为自己的青春调一场因投资引发的冲突投资高手学挖坑?公元前714年,一条消息迅速登上春秋热搜榜郑国国君姬寤生强烈谴责宋国国君子与夷不按时朝见周天子,决定出兵攻打宋国,惩罚这种无礼的行为。消息一出,各方势力一度以为这是哪家不良媒体为博成大事的人,都是人性的高手!1不要暴露自己的野心每个人都有自己的野心,但是定要刻意隐藏起来,不能把它暴露在大庭广众之下。都听过扮猪吃老虎,之所以能成功,最重要的就是靠前期的隐藏,看起来对别人没有伤害,才能让她同一个世界同一个妈!这些妈妈的迷惑行为是如何做到全国统一的过年期间,大家都回家和亲人团圆了。一年里大家忙忙碌碌,难得有这样和父母团聚的时候。但是从小到大在和妈妈的相处中,你有没有被妈妈的一些行为迷惑到呢?今天我们就来说说童年时妈妈的那些迷老年之后,还有异性接近你,都是因为这些原因前言老年之后的生活一直都是很简单,我们不需要想得太复杂,同时我们更应该明白,如果你想要生活幸福的话,有些事情需要提前做好准备,有些时候就要坚持,不要总是觉得生活就是这样子的,如果你
喝大酒伤身,少量喝酒养生,有道理吗?糖尿病患者能不能喝酒?每次一说喝酒,就会遭到反驳,喝酒之人会表示自己已经少量喝酒了,每天少量喝点酒,不伤身反而是有益健康,有养生的功效。相信在生活中,没少听到这样的话语,作为相劝者,并不能认同这样一个说这几件事情,你对孩子做过几件?早上孩子还没睁眼,快起床快起床,上学要迟到了孩子被你惊醒,开始穿衣服。看到孩子慢吞吞的动作,快点穿,快点穿,穿个衣服看你慢的,套上不就行了,穿完衣服快点穿鞋子。孩子按照你的指示开始因为一颗瓜子,我失去了儿子家里这些东西得藏好别给孩子拿到原创孕事养育一个宝宝成长,一定要守住安全底线。危险的食物不乱吃!危险的玩具不能玩!任何时候,家长们都要做好看护,安全第一!前阵子,荔枝新闻就报道了一则新闻,江苏一名4岁的宝宝将西瓜酒店退房时,这几件东西可以带走,包含在房费里,别不好意思随着我们生活的不断进步,很多人在平时也慢慢喜欢上了旅行,很多年轻男女也是非常享受旅行过程中的美好,很多人在游玩的时候就会错过回家的末班车,所以很多景区附近也就会有很多规模不同的酒店梨泰院悲剧后,父母亲最应该教给孩子的一个简单道理这是积极微习惯的第53篇原创文章!谁能想到,在交通如此发达的今天,还会发生梨泰院踩踏事件这样的悲剧呢?年轻人爱扎堆玩是天性,但以生命为代价的玩和闹,就过于沉重了。今天的父母亲,不管鄂尔多斯,沙漠上盛开出最可宝贵的人性之花文桐城一派提到鄂尔多斯,许多人可能立马想到了煤炭草原沙漠以及羊绒衫等,其煤炭储量约占全国总储量的16,煤都之称,名副其实。鄂尔多斯目前是全国文明城市,全国卫生城市,全国园林城市,全祝贺!灵丘红石塄乡上榜啦黄河新闻网大同讯(记者吴星)近日,文化和旅游部第四批全国乡村旅游重点村名单和第二批全国乡村旅游重点镇(乡)名单出炉,大同市灵丘县红石塄乡上榜。红石塄乡位于灵丘县东南部,西依太白巍山太喜欢这本书了!也太喜欢殡葬类的题材了人生道路上,你迷茫的时候,你会怎么做今日头条手写字抄抄抄书练练字静静心今天抄写了遗物整理师这本书中一位患有严重抑郁症的租客自杀的片段,呆在阴暗的角落,躺在垃圾堆里,就那么安静的结束6款常用的电路仿真软件,你喜欢用哪个?电路仿真软件有哪些呢?今天整理了六款常用的电路仿真软件,推荐给大家。需要下载电路仿真软件的用户可以选择。Machining数控仿真软件Machining数控仿真软件初学者通过使用它藏在身边的2个小商机,年轻人别嫌弃,1天实现1000多纯利润很轻松如果说投资不到10万就办个小厂,很多人可能都不会去相信,总觉得投资规模小,即便是能办成的情况下,那在收入方面也不会太高。虽然从客观角度来分析确实是这样,但在现实中,也的确有很多投资他还是个孩子,小学生独自在家录视频作业,家长看到心疼不已作业是检测学生学习效果的最佳途径,随着多媒体教学时代的来临,作业的形式也不再拘泥于书本。口罩原因让网络教学走进千家万户,无论是义务教育,还是高等教育,学生无法按时返校,只能在家里上
友情链接:快好知快生活快百科快传网中准网文好找聚热点快软网