Python中使用定时调度任务(Schedule Jobs)的5种方式

Python中使用定时调度任务(Schedule Jobs)的5种方式

在这里插入图片描述

今天构建的大多数应用程序都需要某种方式的调度机制。轮询 API 或数据库、不断检查系统健康状况、将日志存档等是常见的例子。 KubernetesApache Mesos等使用自动伸缩扩容技术(Auto-scaling)的软件需要检查部署的应用程序的状态,为此它们使用定期运行的存活探针(Liveness Probe)。调度任务需要与业务逻辑解耦,因此我们要使用解耦的执行队列,例如Redis队列。

Python 有几种方法可以定时调度一个任务,这就是我们将在本文中学习的内容。我将使用以下方式讨论调度任务:

  1. 简单循环 (Simple Loops)
  2. 简单循环但是使用了线程 (Simple Loops but Threaded)
  3. 调度库 (Schedule Library)
  4. Python Crontab
  5. RQ 调度器作为解耦队列 (RQ Scheduler as decoupled queues)

简单循环 Simple loops

使用简单循环来实现调度任务这是毫不费力的。使用无限运行的 while 循环定期调用函数可用于调度作业,但这不是最好的方法,不过它是很有效的。可以使用内置time模块的slleep()来延迟执行。不过这并不是大多数作业的调度方式,因为,它看起来很难看,而且与其他方法相比,它的可读性较差。

import time

def task():
    print("Job Completed!")

 while 1:
    task()
    time.sleep(10)

当涉及到每天早上 9:00 或每周三晚上 7:45 等这些日程安排时,事情就变得比较棘手了。

import datetime

def task():
    print("Job Completed!")

 while 1:
    now = datetime.datetime.now()
    # schedule at every wednesday,7:45 pm
    if now.weekday == 3 and now.strftime("%H:%m") == "19:45":
        task()
    # sleep for 6 days
    time.sleep(6 * 24 * 60 * 60)

这是我的第一时间想到的解决办法,不用谢!这种方法的一个问题是这里的逻辑是阻塞的,即一旦在 python 项目中发现这段代码,它就会卡在 while 1 循环中,从而阻塞其他代码的执行。

简单循环但是使用了线程Simple loops but threaded

线程是计算机科学中的一个概念。具有自己指令的小程序由进程执行并独立管理,这就可以解决我们第一种方法的阻塞情况,让我们看看怎么样。

import time
import threading

def task():
    print("Job Completed!")

def schedule():
    while 1:
        task()
        time.sleep(10)

# makes our logic non blocking
thread = threading.Thread(target=schedule)
thread.start()

线程启动后,其底层逻辑无法被主线程修改,因此我们可能需要添加资源,程序通过这些资源可以检查特定场景并根据它们执行逻辑。

定时调度库 Schedule Library

早些时候,我说使用 while 循环进行调度看起来很丑陋,调度库可以解决这个问题。

import schedule
import time

def task():
    print("Job Executing!")

# for every n minutes
schedule.every(10).minutes.do(task)

# every hour
schedule.every().hour.do(task)

# every daya at specific time
schedule.every().day.at("10:30").do(task)

# schedule by name of day
schedule.every().monday.do(task)

# name of day with time
schedule.every().wednesday.at("13:15").do(task)

while True:
    schedule.run_pending()
    time.sleep(1)

正如您所见,通过这样我们可以毫不费力地创建多个调度计划。我特别喜欢创建作业的方式和方法链(Method Chaining),另一方面,这个片段有一个 while 循环,这意味着代码被阻塞,不过我相信你已经知道什么可以帮助我们解决这个问题。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DnYcDMCF-1633830381091)(https://unsplash.com/@redviking509?utm_source=medium&utm_medium=referral)] on Unsplash](https://cdn-images-1.medium.com/max/8634/0*fT92Yr0JununUEEl)

Python Crontab

Liunx 中的 crontab 实用程序是一种易于使用且被广泛接受的调度解决方案。Python 库python-crontab提供了一个 API 来使用 Python 中的 CLI 工具。在crontab中,一个定时调度使用 unix-cron字符串格式(* * * * *)来描述,它是一组五个值的一条线,这表明当作业应该被执行时,python-crontab 将在文件中写入 crontab 的计划转换为写入编程方法。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cqKzTfwc-1633830381094)(https://linuxhint.com/add-crontab-freebsd/)]](https://cdn-images-1.medium.com/max/2824/1*x-Uv0ZZvTMDXTqqvpdEJQQ.png)

from crontab import CronTab

cron = CronTab(user='root')

job = cron.new(command='my_script.sh')

job.hour.every(1)
cron.write()

python-crontab 不会自动保存计划,需要执行 write() 方法来保存计划。还有更多功能,我强烈建议您查看他们的文档。

RQ 调度器 RQ Scheduler

有些任务不能立即执行,因此我们需要根据 LIFO 或 FIFO 等队列系统创建任务队列并弹出任务。python-rq允许我们做到这一点,使用 Redis 作为代理来排队作业。新作业的条目存储为带有信息的哈希映射,例如created_at, enqueued_at, origin, data, description.

排队任务由名为 worker 的程序执行。workers 在 Redis 缓存中也有一个条目,负责将任务出列以及更新 Redis 中的任务状态。任务可以在需要时排队,但要安排它们,我们需要rq-scheduler

from rq_scheduler import Scheduler

queue = Queue('circle', connection=Redis())
scheduler = Scheduler(queue=queue)

scheduler.schedule(
    scheduled_time=datetime.utcnow(), # Time for first execution, in UTC timezone
    func=func,                     # Function to be queued
    args=[arg1, arg2],             # Arguments passed into function when executed
    kwargs={'foo': 'bar'},         # Keyword arguments passed into function when executed
    interval=60,                   # Time before the function is called again, in seconds
    repeat=None,                     # Repeat this number of times (None means repeat forever)
    meta={'foo': 'bar'}            # Arbitrary pickleable data on the job itself
)

RQ worker(RQ 工作器)必须在终端中单独启动或通过 python-rq 工作器启动。一旦任务被触发,就可以在工作终端中看到,在成功和失败场景中都可以使用单独的函数回调。

总结 Conclusion

还有一些用于调度的库,但在这里,我已经讨论了最常见的库。值得一提的是Celery,celery 的另一个优点是用户可以在多个代理之间进行选择。我很感激你读到最后。也可以看看我的其他文章。干杯!

翻译来源: https://python.plainenglish.io/5-ways-to-schedule-jobs-in-python-99de8a80f28e

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 使用Python来编写作业调度算法程序是可行的,首先需要了解需要优先处理的任务,然后按照规定的顺序进行处理。可以使用Python开发框架来实现程序的调度和执行,使用Python的内置模块来实现时序控制,以及支持多任务并发执行。 ### 回答2: 作业调度算法是指根据作业的特定需求和约束条件,以最优的方式来安排作业的执行顺序和时间。下面是用Python编写一个作业调度算法程序的基本思路: 1. 首先,定义作业类(Job)来表示一个作业,包括作业名称、优先级、执行时间等属性。 2. 定义一个作业调度类(JobScheduler),其包含一个作业列表和一些调度算法相关的方法。 3. 提供方法来添加作业、删除作业和获取优先级最高的作业等。 4. 实现不同的调度算法,如先来先服务(FIFO),最短作业优先(SJF),优先级调度(Priority Scheduling)等。具体算法可以根据实际需求进行选择和编写。 5. 根据算法选择执行下一个作业,并更新作业的状态和执行时间。 6. 提供方法来显示当前作业列表和作业的执行结果。 下面是一个简单的示例代码,使用最短作业优先算法来调度作业: ```python class Job: def __init__(self, name, priority, time): self.name = name self.priority = priority self.time = time class JobScheduler: def __init__(self): self.jobs = [] def add_job(self, job): self.jobs.append(job) def remove_job(self, job): self.jobs.remove(job) def get_next_job(self): self.jobs.sort(key=lambda x: x.time) # 按执行时间排序 return self.jobs[0] def schedule_jobs(self): while self.jobs: next_job = self.get_next_job() # 获取优先级最高的作业 print("执行作业:", next_job.name) next_job.time -= 1 # 执行时间减1 if next_job.time == 0: self.remove_job(next_job) # 完成作业 scheduler = JobScheduler() job1 = Job("Job 1", 2, 5) job2 = Job("Job 2", 1, 3) job3 = Job("Job 3", 3, 4) scheduler.add_job(job1) scheduler.add_job(job2) scheduler.add_job(job3) scheduler.schedule_jobs() ``` 该程序会根据短作业优先算法来调度作业的执行顺序,每次执行一个作业,直到所有作业都完成为止。以上就是用Python编写作业调度算法程序的基本思路和示例代码。 ### 回答3: 作业调度算法是操作系统的重要概念之一,它用于决定多个作业的执行顺序,其包括作业的优先级和到达时间等因素。下面是一个使用Python编写的作业调度算法程序示例: ```python class Job: def __init__(self, id, priority, arrival_time): self.id = id self.priority = priority self.arrival_time = arrival_time def schedule(jobs): # 按照作业的优先级和到达时间排序 jobs.sort(key=lambda x: (x.priority, x.arrival_time)) # 打印作业执行顺序 for job in jobs: print("执行作业{},优先级:{},到达时间:{}".format(job.id, job.priority, job.arrival_time)) # 创建作业列表 jobs = [ Job(1, 3, 5), Job(2, 1, 2), Job(3, 2, 3) ] # 调用作业调度函数 schedule(jobs) ``` 上述程序,首先定义了一个作业类Job,其包含了作业的ID、优先级和到达时间等属性。然后使用sort函数对作业列表进行排序,排序规则为先按优先级升序,再按到达时间升序。最后通过遍历作业列表,按照排序结果输出每个作业的相关信息。 对于输入的作业列表,程序将根据作业的优先级和到达时间,按照升序的方式进行排序,然后按序输出每个作业的ID、优先级和到达时间等信息,这样就得到了作业的执行顺序。具体的作业调度策略可以根据实际需求进行修改和扩展。 需要注意的是,上述示例只是作业调度算法的简单示例,实际的作业调度问题可能更加复杂,需要考虑更多因素。这只是一个基于优先级和到达时间的简单示例,仅供参考。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值