在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Celery Beat 的周期調度機制及實現(xiàn)原理

科技綠洲 ? 來源:Python實用寶典 ? 作者:Python實用寶典 ? 2023-10-31 15:24 ? 次閱讀

Celery 是一個簡單、靈活且可靠的,處理大量消息的分布式系統(tǒng),它是一個專注于實時處理的任務隊列,同時也支持任務調度。

為了講解 Celery Beat 的周期調度機制及實現(xiàn)原理,我們會基于Django從制作一個簡單的周期任務開始,然后一步一步拆解 Celery Beat 的源代碼。

相關前置應用知識,可以閱讀以下文章:

  1. 實戰(zhàn)教程!Django Celery 異步與定時任務
  2. Python Celery異步快速下載股票數(shù)據(jù)

1.Celery 簡單周期任務示例

在 celery_app.tasks.py 中添加如下任務:

@shared_task
def pythondict_task():
    print("pythondict_task")

在 django.celery.py 文件中添加如下配置:

from celery_django import settings
from datetime import timedelta


app.autodiscover_tasks(lambda : settings.INSTALLED_APPS)

CELERYBEAT_SCHEDULE = {
    'pythondict_task': {
        'task': 'celery_app.tasks.pythondict_task',
        'schedule': timedelta(seconds=3),
    },
}

app.conf.update(CELERYBEAT_SCHEDULE=CELERYBEAT_SCHEDULE)

至此,配置完成,此時,先啟動 Celery Beat 定時任務命令:

celery beat -A celery_django -S django

然后打開第二個終端進程啟動消費者:

celery -A celery_django worker

此時在worker的終端上就會輸出類似如下的信息

[2021-07-11 16:34:11,546: WARNING/PoolWorker-3] pythondict_task
[2021-07-11 16:34:11,550: WARNING/PoolWorker-4] pythondict_task
[2021-07-11 16:34:11,551: WARNING/PoolWorker-2] pythondict_task
[2021-07-11 16:34:11,560: WARNING/PoolWorker-1] pythondict_task

看到結果正常輸出,說明任務成功定時執(zhí)行。

2.源碼剖析

為了明白 Celery Beat 是如何實現(xiàn)周期任務調度的,我們需要從 Celery 源碼入手。

當你執(zhí)行 Celery Beat 啟動命令的時候,到底發(fā)生了什么?

celery beat -A celery_django -S django

當你執(zhí)行這個命令的時候,Celery/bin/celery.py 中的 CeleryCommand 類接收到命令后,會選擇 beat 對應的類執(zhí)行如下代碼:

# Python 實用寶典
# https://pythondict.com

from celery.bin.beat import beat

class CeleryCommand(Command):
    commands = {
        # ...
        'beat': beat,
        # ...
    }
    # ...
    def execute(self, command, argv=None):
        try:
            cls = self.commands[command]
        except KeyError:
            cls, argv = self.commands['help'], ['help']
        cls = self.commands.get(command) or self.commands['help']
        try:
            return cls(
                app=self.app, on_error=self.on_error,
                no_color=self.no_color, quiet=self.quiet,
                on_usage_error=partial(self.on_usage_error, command=command),
            ).run_from_argv(self.prog_name, argv[1:], command=argv[0])
        except self.UsageError as exc:
            self.on_usage_error(exc)
            return exc.status
        except self.Error as exc:
            self.on_error(exc)
            return exc.status

此時cls對應的是beat類,通過查看位于bin/beat.py中的 beat 類可知,該類只重寫了run方法和add_arguments方法。

所以此時執(zhí)行的 run_from_argv 方法是 beat 繼承的 Command 的 run_from_argv 方法:

# Python 實用寶典
# https://pythondict.com

def run_from_argv(self, prog_name, argv=None, command=None):
    return self.handle_argv(prog_name, sys.argv if argv is None else argv, command)

該方法中會調用 Command 的 handle_argv 方法,而該方法在經(jīng)過相關參數(shù)處理后會調用 self(*args, **options) 到 call 函數(shù):

# Python 實用寶典
    # https://pythondict.com
    
    def handle_argv(self, prog_name, argv, command=None):
        """Parse command-line arguments from ``argv`` and dispatch
        to :meth:`run`.

        :param prog_name: The program name (``argv[0]``).
        :param argv: Command arguments.

        Exits with an error message if :attr:`supports_args` is disabled
        and ``argv`` contains positional arguments.

        """
        options, args = self.prepare_args(
            *self.parse_options(prog_name, argv, command))
        return self(*args, **options)

Command 類的 __call__函數(shù):

# Python 實用寶典
    # https://pythondict.com
    
    def __call__(self, *args, **kwargs):
        random.seed() # maybe we were forked.
        self.verify_args(args)
        try:
            ret = self.run(*args, **kwargs)
            return ret if ret is not None else EX_OK
        except self.UsageError as exc:
            self.on_usage_error(exc)
            return exc.status
        except self.Error as exc:
            self.on_error(exc)
            return exc.status

可見,在該函數(shù)中會調用到run方法,此時調用的run方法就是beat類中重寫的run方法,查看該方法:

# Python 實用寶典
# https://pythondict.com
    
class beat(Command):
    """Start the beat periodic task scheduler.

    Examples::

        celery beat -l info
        celery beat -s /var/run/celery/beat-schedule --detach
        celery beat -S djcelery.schedulers.DatabaseScheduler

    """
    doc = __doc__
    enable_config_from_cmdline = True
    supports_args = False

    def run(self, detach=False, logfile=None, pidfile=None, uid=None,
            gid=None, umask=None, working_directory=None, **kwargs):
        # 是否開啟后臺運行
        if not detach:
            maybe_drop_privileges(uid=uid, gid=gid)
        workdir = working_directory
        kwargs.pop('app', None)
        # 設定偏函數(shù)
        beat = partial(self.app.Beat,
                       logfile=logfile, pidfile=pidfile, **kwargs)

        if detach:
            with detached(logfile, pidfile, uid, gid, umask, workdir):
                return beat().run() # 后臺運行
        else:
            return beat().run() # 立即運行

這里引用了偏函數(shù)的知識,偏函數(shù)就是從基函數(shù)創(chuàng)建一個新的帶默認參數(shù)的函數(shù),詳細可見廖雪峰老師的介紹:
https://www.liaoxuefeng.com/wiki/1016959663602400/1017454145929440

可見,此時創(chuàng)建了app的Beat方法的偏函數(shù),并通過 .run 函數(shù)執(zhí)行啟動 beat 進程,首先看看這個 beat 方法:

# Python 實用寶典
    # https://pythondict.com
    @cached_property
    def Beat(self, **kwargs):
        # 導入celery.apps.beat:Beat類
        return self.subclass_with_self('celery.apps.beat:Beat')

可以看到此時就實例化了 celery.apps.beat 中的 Beat 類,并調用了該實例的 run 方法:

# Python 實用寶典
    # https://pythondict.com
    def run(self):
        print(str(self.colored.cyan(
            'celery beat v{0} is starting.'.format(VERSION_BANNER))))
        # 初始化loader
        self.init_loader()
        # 設置進程
        self.set_process_title()
        # 開啟任務調度
        self.start_scheduler()

init_loader 中,會導入默認的modules,此時會引入相關的定時任務,這些不是本文重點。我們重點看 start_scheduler 是如何開啟任務調度的:

# Python 實用寶典
    # https://pythondict.com
    def start_scheduler(self):
        c = self.colored
        if self.pidfile: # 是否設定了pid文件
            platforms.create_pidlock(self.pidfile) # 創(chuàng)建pid文件
        # 初始化service
        beat = self.Service(app=self.app,
                            max_interval=self.max_interval,
                            scheduler_cls=self.scheduler_cls,
                            schedule_filename=self.schedule)
        
        # 打印啟動信息
        print(str(c.blue('__ ', c.magenta('-'),
                  c.blue(' ... __ '), c.magenta('-'),
                  c.blue(' _n'),
                  c.reset(self.startup_info(beat)))))
        # 開啟日志
        self.setup_logging()
        if self.socket_timeout:
            logger.debug('Setting default socket timeout to %r',
                         self.socket_timeout)
            # 設置超時
            socket.setdefaulttimeout(self.socket_timeout)
        try:
            # 注冊handler
            self.install_sync_handler(beat)
            # 開啟beat
            beat.start()
        except Exception as exc:
            logger.critical('beat raised exception %s: %r',
                            exc.__class__, exc,
                            exc_info=True)

我們看下beat是如何開啟的:

# Python 實用寶典
    # https://pythondict.com
    def start(self, embedded_process=False, drift=-0.010):
        info('beat: Starting...')
        # 打印最大間隔時間
        debug('beat: Ticking with max interval- >%s',
              humanize_seconds(self.scheduler.max_interval))
        
        # 通知注冊該signal的函數(shù)
        signals.beat_init.send(sender=self)
        if embedded_process:
            signals.beat_embedded_init.send(sender=self)
            platforms.set_process_title('celery beat')

        try:
            while not self._is_shutdown.is_set():
                # 調用scheduler.tick()函數(shù)檢查還剩多余時間
                interval = self.scheduler.tick()
                interval = interval + drift if interval else interval
                # 如果大于0
                if interval and interval > 0:
                    debug('beat: Waking up %s.',
                          humanize_seconds(interval, prefix='in '))
                    # 休眠
                    time.sleep(interval)
                    if self.scheduler.should_sync():
                        self.scheduler._do_sync()
        except (KeyboardInterrupt, SystemExit):
            self._is_shutdown.set()
        finally:
            self.sync()

這里重點看 self.scheduler.tick() 方法:

# Python 實用寶典
    # https://pythondict.com
    def tick(self):
        """Run a tick, that is one iteration of the scheduler.

        Executes all due tasks.

        """
        remaining_times = []
        try:
            # 遍歷每個周期任務設定
            for entry in values(self.schedule):
                # 下次運行時間
                next_time_to_run = self.maybe_due(entry, self.publisher)
                if next_time_to_run:
                    remaining_times.append(next_time_to_run)
        except RuntimeError:
            pass

        return min(remaining_times + [self.max_interval])

這里通過 self.schedule 拿到了所有存放在用 shelve 寫入的 celerybeat-schedule 文件的定時任務,遍歷所有定時任務,調用 self.maybe_due 方法:

# Python 實用寶典
    # https://pythondict.com
    def maybe_due(self, entry, publisher=None):
        # 是否到達運行時間
        is_due, next_time_to_run = entry.is_due()

        if is_due:
            # 打印任務發(fā)送日志
            info('Scheduler: Sending due task %s (%s)', entry.name, entry.task)
            try:
                # 執(zhí)行任務
                result = self.apply_async(entry, publisher=publisher)
            except Exception as exc:
                error('Message Error: %sn%s',
                      exc, traceback.format_stack(), exc_info=True)
            else:
                debug('%s sent. id- >%s', entry.task, result.id)
        return next_time_to_run

可以看到,此處會判斷任務是否到達定時時間,如果是的話,會調用 apply_async 調用Worker執(zhí)行任務。如果不是,則返回下次運行時間,讓 Beat 進程進行 Sleep,減少進程資源消耗。

到此,我們就講解完了 Celery Beat 在周期定時任務的檢測調度機制,怎么樣,小伙伴們有沒有什么疑惑?可以在下方留言區(qū)留言一起討論哦。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 終端
    +關注

    關注

    1

    文章

    1140

    瀏覽量

    29920
  • 源代碼
    +關注

    關注

    96

    文章

    2945

    瀏覽量

    66793
  • python
    +關注

    關注

    56

    文章

    4797

    瀏覽量

    84787
收藏 人收藏

    評論

    相關推薦

    uc/os任務調度機制

    uc/os任務調度機制uc/OS 任務調度機制 內核的核心任務是任務調度機制,為了對uC/OS進行分析,我們從任務調度開始。在uC/OS中,一個任務通常是一個無限循環(huán),程序具有如下的結
    發(fā)表于 07-07 09:46

    UCOS之任務調度機制

    UCOS之任務調度機制
    發(fā)表于 05-30 07:56

    VxWorks系統(tǒng)的任務調度機制

    針對多任務系統(tǒng)而言,調度是指根據(jù)一定的算法.將CPU 分配給符合條件的任務使用,不同的系統(tǒng)任務調度機制不同。本文介紹VxWorks系統(tǒng)的任務調度策略和算法.分析優(yōu)先級倒置產(chǎn)
    發(fā)表于 12-16 14:11 ?10次下載

    Linux與VxWorks任務調度機制分析

    Linux與VxWorks任務調度機制分析
    發(fā)表于 03-28 09:52 ?19次下載

    嵌入式實時操作系統(tǒng)VxWorks內核調度機制研究

    嵌入式實時操作系統(tǒng)VxWorks內核調度機制研究
    發(fā)表于 03-29 12:26 ?13次下載

    μC/OS-II 任務調度機制的改進

    介紹μC/OS-II 任務調度機制,并提出一種改進方法,使μC/OS-II變成一個兼?zhèn)鋵崟r與分時任務調度機制的操作系統(tǒng); 論述改進后系統(tǒng)的特點和要注意的問題,給出部分源代碼。
    發(fā)表于 04-15 11:21 ?14次下載

    高可信賴實時操作系統(tǒng)的防危調度機制

    為增強實時操作系統(tǒng)的防危性,在分析現(xiàn)有調度機制的基礎上,探討了最大關鍵度優(yōu)先的調度算法,該算法是一種混合型的優(yōu)先級實時調度算法,由靜態(tài)優(yōu)先級、動態(tài)子優(yōu)先級和
    發(fā)表于 05-16 11:52 ?10次下載

    基于輪循機制和RED的語音流調度機制

           本文提出了一種新的VoIP業(yè)務流調度機制(RR-RED),通過隨機早期檢測(RED)和輪循機制(Round Robin)控制主動丟包。該機制很好的繼承了R
    發(fā)表于 09-03 08:58 ?7次下載

    Li nux與VxWorks任務調度機制分析

    分析了Linux和VxWorks兩種多任務操作系統(tǒng)任務調度機制的異同,從任務控制塊、調度的時機、調度的優(yōu)先級和調度的策略方面進行了詳細的分析和對比。分析了VxWorks和Linux在P
    發(fā)表于 11-13 17:54 ?10次下載

    VxWorks系統(tǒng)的任務調度機制

    針對多任務系統(tǒng)而言,調度是指根據(jù)一定的算法.將CPU 分配給符合條件的任務使用,不同的系統(tǒng)任務調度機制不同。本文介紹VxWorks系統(tǒng)的任務調度策略和算法.分析優(yōu)先級倒置產(chǎn)生
    發(fā)表于 11-27 16:26 ?13次下載

    嵌入式實時操作系統(tǒng)VxWorks內核調度機制分析

    本文簡要介紹了多任務內核,重點分析了嵌入式實時操作系統(tǒng)VxWorks的內核調度機制——優(yōu)先級搶占調度和時間片輪轉調度算法。
    發(fā)表于 12-11 16:15 ?14次下載

    Windows CE陷阱調度機制

     一.什么是陷阱調度機制?        一般來說,嵌入式操作系統(tǒng)主要由兩部分組成:運行在核心態(tài)的內核系統(tǒng)和運行在用戶態(tài)的環(huán)境子系統(tǒng)組成。因
    發(fā)表于 08-27 14:38 ?647次閱讀

    基于動態(tài)概率休眠調度機制的WSNs拓撲控制算法_韓瑞艷

    基于動態(tài)概率休眠調度機制的WSNs拓撲控制算法_韓瑞艷
    發(fā)表于 03-19 19:19 ?0次下載

    虛擬計算資源調度機制研究

    針對基于Xen的vCPU調度機制對虛擬機網(wǎng)絡性能的影響進行了深入研究和分析。提出一種高效、準確、輕量級的網(wǎng)絡排隊敏感類型虛擬機(NSVM)識別方法,可根據(jù)當前虛擬機I/O傳輸特征將容易受到影響
    發(fā)表于 02-08 17:08 ?0次下載
    虛擬計算資源<b class='flag-5'>調度機制</b>研究

    NB―IoT物理控制信道NB―PDCCH及資源調度機制

    NB―IoT物理控制信道NB―PDCCH及資源調度機制(現(xiàn)代電源技術試題及答案)-NB―IoT物理控制信道NB―PDCCH及資源調度機制 ? ? ? ? ?
    發(fā)表于 08-31 19:56 ?13次下載
    NB―IoT物理控制信道NB―PDCCH及資源<b class='flag-5'>調度機制</b>
    主站蜘蛛池模板: 日本加勒比高清一本大道| 天天操天天干天天透| 免费观看黄色网页| 久久综合九色综合欧美狠狠| 国模私拍一区二区| 俺去插| 天天摸天天草| 福利在线观看| 午夜视频网址| 91久久精品青青草原伊人| 欧美色操| 狠狠色丁香久久综合婷婷| 97色在线视频| 色女仆影院| 5252欧美在线观看| 四虎电影院| 色视频网站人成免费| 欧美色乱| 成年毛片| 女女同免费播放毛片| 欧美最猛性xxxx免费| 久久精品人人爽人人爽快| 婷婷色在线观看| 口述他拿舌头进去我下面好爽| 高清欧美一级在线观看| 天天操 夜夜操| 午夜欧美性视频在线播放| 精品国产1000部91麻豆| 四虎黄色片| 国产欧美一区二区三区观看| 天天摸天天躁天天添天天爽 | 性欧美在线| 欧美三级一级| 99精品久久久久久久婷婷| 精品久久看| 美女扒开腿让男人桶尿口| 日韩色爱| 真实的国产乱xxxx在线| 69japanese日本100| 伊人久久网站| 久久精品综合网|