基于 Redis 的任務(wù)排隊時間統(tǒng)計

問題

基于 Redis 的優(yōu)先級隊列這篇文章中,我們使用 sorted set 實現(xiàn)了一個優(yōu)先級隊列?,F(xiàn)在,考慮如下問題:

在一個任務(wù)調(diào)度系統(tǒng)中,任務(wù)進入隊列排隊,然后等待被調(diào)度出隊列。為了衡量調(diào)度效率,一個指標是任務(wù)的平均排隊時間。那么,如何統(tǒng)計每個任務(wù)的排隊時間以及這些任務(wù)的平均排隊時間呢?

解決方案

為了統(tǒng)計每個任務(wù)的排隊時間,我們需要知道任務(wù)的入隊時間以及出隊時間,這兩個時間的差值就是這個任務(wù)的排隊時間。我們?nèi)匀皇褂?sorted set 來記錄任務(wù)的入隊或出隊時間,只不過這個時候 sorted set 中元素的 score 不再是優(yōu)先級,而是任務(wù)的入隊或出隊時間。

代碼實現(xiàn)

下面是一個可能的代碼實現(xiàn):

class QueuingTimeStat(object):

    def __init__(self, redis_client, redis_key, namespace='schedule'):
        self.client = redis_client
        self.key = '%s:%s' % (namespace, redis_key)

    def _clean(self):
        """清理一天之前的記錄"""
        now = time.time()
        self.client.zremrangebyscore(self.key, 0, now - 3600 * 24)

    def add_start(self, task_id, timestamp=None):
        self._clean()
        member = '%s:%s' % (task_id, 'start')
        timestamp = time.time() if timestamp is None else timestamp
        self.client.zadd(self.key, timestamp, member)

    def add_end(self, task_id, timestamp=None):
        self._clean()
        member = '%s:%s' % (task_id, 'end')
        timestamp = time.time() if timestamp is None else timestamp
        self.client.zadd(self.key, timestamp, member)

    def average_delay(self, window):
        now = time.time()
        results = self.client.zrangebyscore(self.key, now - window, now, withscores=True)
        # [(value, score), ...]
        sorted_results = sorted(results, key=lambda x: x[0])
        group_results = groupby(sorted_results, key=lambda x: x[0].rsplit(':', 1)[0])
        total = 0.0
        count = 0
        for task_id, sub_group in group_results:
            pairs = tuple(sub_group)
            if len(pairs) == 2:
                count += 1
                total += abs(pairs[0][1] - pairs[1][1])
            else:
                if pairs[0][0].endswith('start'):
                    count += 1
                    total += now - pairs[0][1]
        return total / count if count > 0 else 0

在上面的代碼中,task_id 是任務(wù)的唯一標識。task_id:start 用于記錄任務(wù)的入隊時間,task_id:end 用于記錄任務(wù)的出隊時間。average_delay 用于統(tǒng)計最近任務(wù)的平均排隊時間,該方法提供了時間窗口 window 參數(shù),時間窗口越大,則平均排隊時間變化曲線越平滑。另外,為了降低對內(nèi)存的消耗,每次記錄入隊或出隊時間的時候,會清理一天之前的入隊出隊時間記錄。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • GCD調(diào)度隊列是執(zhí)行任務(wù)的強大工具。調(diào)度隊列允許您相對于調(diào)度者異步或者同步的執(zhí)行任意代碼塊。您能夠使用調(diào)度隊列來執(zhí)...
    坤坤同學閱讀 6,745評論 1 3
  • 第三章 Java內(nèi)存模型 3.1 Java內(nèi)存模型的基礎(chǔ) 通信在共享內(nèi)存的模型里,通過寫-讀內(nèi)存中的公共狀態(tài)進行隱...
    澤毛閱讀 4,495評論 2 21
  • 從哪說起呢? 單純講多線程編程真的不知道從哪下嘴。。 不如我直接引用一個最簡單的問題,以這個作為切入點好了 在ma...
    Mr_Baymax閱讀 2,903評論 1 17
  • 第6問:怎樣管理微信好友才能“投其所好”? 上次課講到了各位微信銷售伙伴,要擅于使用微信提供的、管理微信好友的功能...
    阿羅的甜蜜圈閱讀 125評論 0 0
  • 看人看事,看你是什么樣的人,從她的做事就能看出來,她做的事只能更加堅定自己的選擇! 高三那年,我還是一個學生會的部...
    末日情閱讀 559評論 0 0

友情鏈接更多精彩內(nèi)容