• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            posts - 14,  comments - 57,  trackbacks - 0
              最新?lián)Q了個(gè)項(xiàng)目組,閱讀代碼后,發(fā)現(xiàn)Server端代碼居然沒有事件和定時(shí)器。由于沒有事件,所以各個(gè)模塊代碼互相調(diào)用的地方特別多,導(dǎo)致代碼結(jié)構(gòu)混亂,所有代碼都放在一塊,亂成一鍋粥了。
            沒有定時(shí)器,所有需要定時(shí)的任務(wù),都只能添加類似OnUpdate的函數(shù),在主循環(huán)的時(shí)候執(zhí)行。定時(shí)需求少的時(shí)候,看不出明顯的問題,但是一旦這種需求多了,尤其是很多內(nèi)部對(duì)象有定時(shí)需求的時(shí)候,
            這個(gè)問題就比較明顯了,寫好了OnUpdate后,還要建立一條從主循環(huán)MainLoop到自身OnUpdate的調(diào)用鏈。
             
              事件其實(shí)就是一個(gè)廣播和訂閱的關(guān)系,Delegate就是實(shí)現(xiàn)這樣一套機(jī)制的利器,目前Delegate的實(shí)現(xiàn)主要有2種,一種是CodeProject上的一個(gè)FastDelegate實(shí)現(xiàn),另外一個(gè)比較典型的實(shí)現(xiàn)就是boost的
            實(shí)現(xiàn)了,無論采取哪種實(shí)現(xiàn)方案,實(shí)現(xiàn)難度都不算太大。
              Server當(dāng)前框架對(duì)定時(shí)器無任何支持,只有一個(gè)DoMainLoop的函數(shù)可以派生來運(yùn)行自己的定時(shí)邏輯。
              我原來都是用的ACE封裝的組件,用了一段時(shí)間也沒發(fā)現(xiàn)明顯問題,不過ACE的定時(shí)器不太適合在這個(gè)新項(xiàng)目用,主要原因有如下幾點(diǎn):
              1、ACE庫太大了,不想僅僅為了定時(shí)器引入一個(gè)這么龐大的庫。
              2、ACE的定時(shí)器需要額外啟動(dòng)一個(gè)定時(shí)器線程,定時(shí)任務(wù)是在定時(shí)器線程跑的,而我們的項(xiàng)目邏輯其實(shí)是在單個(gè)線程運(yùn)行的,如果直接采用ACE定時(shí)器,會(huì)給邏輯帶來額外的復(fù)雜度。由于整個(gè)邏輯線程的框架是公共模塊,手頭也沒有代碼,所以將定時(shí)器線程的任務(wù)發(fā)送到主邏輯線程運(yùn)行也是不可行的。
              3、ACE的定時(shí)器有很多種,TIMER_QUEUE、TIMER_WHELL、TIMER_HEAP等,個(gè)人感覺這些定時(shí)器的插入、取消操作都比較耗時(shí),加以改裝放到主線程run的帶價(jià)將會(huì)很大。

            其實(shí)linux內(nèi)核就有一個(gè)比較高性能的定時(shí)器,代碼在kernel/Timer.c里, 2.6內(nèi)核的定時(shí)器代碼更是簡潔。
            linux的定時(shí)任務(wù)都是以jiffie 為單位的,linux將所有定時(shí)任務(wù)分為5個(gè)階梯,
            struct tvec {
                struct list_head vec[TVN_SIZE];
            };

            struct tvec_root {
                struct list_head vec[TVR_SIZE];
            };

            struct tvec_base {
                spinlock_t lock;
                struct timer_list *running_timer;
                unsigned long timer_jiffies;
                struct tvec_root tv1;
                struct tvec tv2;
                struct tvec tv3;
                struct tvec tv4;
                struct tvec tv5;
            } ____cacheline_aligned;

            對(duì)一個(gè)新的定時(shí)任務(wù),處理方法如下:
            static void internal_add_timer(struct tvec_base *base, struct timer_list *timer)
            {
                unsigned long expires = timer->expires;
                unsigned long idx = expires - base->timer_jiffies;
                struct list_head *vec;

                if (idx < TVR_SIZE) {
                    int i = expires & TVR_MASK;
                    vec = base->tv1.vec + i;
                } else if (idx < 1 << (TVR_BITS + TVN_BITS)) {
                    int i = (expires >> TVR_BITS) & TVN_MASK;
                    vec = base->tv2.vec + i;
                } else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS)) {
                    int i = (expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK;
                    vec = base->tv3.vec + i;
                } else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) {
                    int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK;
                    vec = base->tv4.vec + i;
                } else if ((signed long) idx < 0) {
                    /*
                     * Can happen if you add a timer with expires == jiffies,
                     * or you set a timer to go off in the past
                     */
                    vec = base->tv1.vec + (base->timer_jiffies & TVR_MASK);
                } else {
                    int i;
                    /* If the timeout is larger than 0xffffffff on 64-bit
                     * architectures then we use the maximum timeout:
                     */
                    if (idx > 0xffffffffUL) {
                        idx = 0xffffffffUL;
                        expires = idx + base->timer_jiffies;
                    }
                    i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;
                    vec = base->tv5.vec + i;
                }
                /*
                 * Timers are FIFO:
                 */
                list_add_tail(&timer->entry, vec);
            }
            從上可以看到Linux對(duì)定時(shí)器的處理:對(duì)即將在TVR_SIZE 個(gè)jiffies內(nèi)到達(dá)的定時(shí)任務(wù),將它掛到第一組tv1 下,具體就是掛到expires & TVR_MASK 對(duì)應(yīng)的列表上去。
            同一個(gè)jiffies到達(dá)的定時(shí)器是掛在同一個(gè)鏈表的。
            同理,掛到第二個(gè)組的是 到期時(shí)間小于 1 << (TVR_BITS + TVN_BITS) jiffies的。
            掛到第三個(gè)組的是 到期時(shí)間小于1 << (TVR_BITS + 2 * TVN_BITS) jiffies的。
            掛到第四個(gè)組的是 到期時(shí)間小于 1 << (TVR_BITS + 3 * TVN_BITS) jiffies的。
            超過1 << (TVR_BITS + 3 * TVN_BITS) 的掛到第五組。
            這樣,所有到期的任務(wù)都會(huì)在第一組。任何時(shí)刻都可以直接通過當(dāng)前jiffies&TVR_SIZE 來找到需要運(yùn)行的定時(shí)器任務(wù)列表,定時(shí)器的插入效率就是O(1)。

            下面是定時(shí)器的運(yùn)行代碼:
            static int cascade(struct tvec_base *base, struct tvec *tv, int index)
            {
                /* cascade all the timers from tv up one level */
                struct timer_list *timer, *tmp;
                struct list_head tv_list;

                list_replace_init(tv->vec + index, &tv_list);

                /*
                 * We are removing _all_ timers from the list, so we
                 * don't have to detach them individually.
                 */
                list_for_each_entry_safe(timer, tmp, &tv_list, entry) {
                    BUG_ON(tbase_get_base(timer->base) != base);
                    internal_add_timer(base, timer);
                }

                return index;
            }

            #define INDEX(N) ((base->timer_jiffies >> (TVR_BITS + (N) * TVN_BITS)) & TVN_MASK)

            /**
             * __run_timers - run all expired timers (if any) on this CPU.
             * @base: the timer vector to be processed.
             *
             * This function cascades all vectors and executes all expired timer
             * vectors.
             */
            static inline void __run_timers(struct tvec_base *base)
            {
                struct timer_list *timer;

                spin_lock_irq(&base->lock);
                while (time_after_eq(jiffies, base->timer_jiffies)) {
                    struct list_head work_list;
                    struct list_head *head = &work_list;
                    int index = base->timer_jiffies & TVR_MASK;

                    /*
                     * Cascade timers:
                     */
                    if (!index &&
                        (!cascade(base, &base->tv2, INDEX(0))) &&
                            (!cascade(base, &base->tv3, INDEX(1))) &&
                                !cascade(base, &base->tv4, INDEX(2)))
                        cascade(base, &base->tv5, INDEX(3));
                    ++base->timer_jiffies;
                    list_replace_init(base->tv1.vec + index, &work_list);
                    while (!list_empty(head)) {
                        void (*fn)(unsigned long);
                        unsigned long data;

                        timer = list_first_entry(head, struct timer_list,entry);
                        fn = timer->function;
                        data = timer->data;

                        timer_stats_account_timer(timer);

                        set_running_timer(base, timer);
                        detach_timer(timer, 1);
                        spin_unlock_irq(&base->lock);
                        {
                            int preempt_count = preempt_count();
                            fn(data);
                            if (preempt_count != preempt_count()) {
                                printk(KERN_ERR "huh, entered %p "
                                       "with preempt_count %08x, exited"
                                       " with %08x?\n",
                                       fn, preempt_count,
                                       preempt_count());
                                BUG();
                            }
                        }
                        spin_lock_irq(&base->lock);
                    }
                }
                set_running_timer(base, NULL);
                spin_unlock_irq(&base->lock);
            }
            當(dāng)?shù)谝唤M運(yùn)行完一輪后,需要將tv2的一組新的定時(shí)任務(wù)加到第一組。這就好比時(shí)鐘的指針,秒針運(yùn)行一圈后,分針步進(jìn)一格,后續(xù)的調(diào)整都是類似。
            cascade 就是負(fù)責(zé)將下一組的定時(shí)任務(wù)添加到前面的任務(wù)階梯。只有當(dāng)?shù)谝惠喌亩〞r(shí)任務(wù)全部運(yùn)行完畢后,才會(huì)需要從第二輪調(diào)入新的任務(wù),只有第二級(jí)別的任務(wù)都調(diào)入完畢后,才需要從第三輪的定時(shí)任務(wù)調(diào)入新的任務(wù):
             if (!index &&
                        (!cascade(base, &base->tv2, INDEX(0))) &&
                            (!cascade(base, &base->tv3, INDEX(1))) &&
                                !cascade(base, &base->tv4, INDEX(2)))
                        cascade(base, &base->tv5, INDEX(3));

            這就是負(fù)責(zé)調(diào)整的代碼,相當(dāng)?shù)暮啙崱?br>參照上述代碼實(shí)現(xiàn)一個(gè)定時(shí)器后,加入4000個(gè)定時(shí)任務(wù):
                for(int i = 1; i < 4000; i++)
                {
                    g_TimerHandle[i] = g_timerManager.setTimer(&tmpSink1, i, i*10, "ss");
                }
            從10毫秒到4000*10毫秒,運(yùn)行后,測試下性能,
            函數(shù)名                                    執(zhí)行次數(shù)    最小時(shí)間     平均時(shí)間       最大時(shí)間
            TimerManager::runTimer    2170566        10              10               3046   
            可以看到,除了個(gè)別時(shí)間是因?yàn)榫€程切換導(dǎo)致數(shù)據(jù)比較大外,平均每次運(yùn)行runTimer的時(shí)間是10微秒。
            這個(gè)時(shí)間還包括每個(gè)定時(shí)器的執(zhí)行消耗,效率還是不錯(cuò)的。
            posted on 2011-03-13 22:06 feixuwu 閱讀(2099) 評(píng)論(0)  編輯 收藏 引用 所屬分類: 游戲開發(fā)
            <2011年3月>
            272812345
            6789101112
            13141516171819
            20212223242526
            272829303112
            3456789

            文章轉(zhuǎn)載請(qǐng)注明出處

            常用鏈接

            留言簿(11)

            隨筆分類

            隨筆檔案

            搜索

            •  

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            亚洲人成无码久久电影网站| 久久精品国产一区二区三区不卡 | 国产婷婷成人久久Av免费高清| 亚洲精品无码久久久久久| 久久精品成人免费看| 2021国产精品午夜久久| 91精品国产91热久久久久福利| 久久久久久无码国产精品中文字幕| 久久精品国产久精国产一老狼| 丁香狠狠色婷婷久久综合| 四虎国产精品成人免费久久| 青青草国产精品久久| 亚洲中文精品久久久久久不卡| 91精品国产综合久久香蕉 | 久久精品国产亚洲AV影院| 青青草原综合久久| 久久不见久久见免费视频7| 一级做a爰片久久毛片看看 | 久久久久久久97| 久久精品一区二区三区AV| 精品水蜜桃久久久久久久| 99国产精品久久久久久久成人热| 色欲综合久久躁天天躁| 精品久久久久久国产牛牛app| 久久A级毛片免费观看| 亚洲国产精品无码久久98| 97精品伊人久久大香线蕉| 人妻无码精品久久亚瑟影视| 久久久这里只有精品加勒比| 色综合合久久天天给综看| 欧美亚洲另类久久综合婷婷| 国产香蕉97碰碰久久人人| 精品久久久久久国产三级| 久久人妻少妇嫩草AV蜜桃| 久久国产成人| 欧美大战日韩91综合一区婷婷久久青草| 88久久精品无码一区二区毛片| 丁香久久婷婷国产午夜视频| 国内精品免费久久影院| 久久久久久亚洲精品不卡| 婷婷久久五月天|