schedule 不适合长期运行,因其无后台线程或事件循环,需持续调用 run_pending();APScheduler 适合 I/O 密集型任务但需显式启停;aioschedule 适配异步服务但要求全异步;Linux 下 cron + systemd 最稳定,需自行处理日志、锁和环境。

schedule 库跑着跑着就停了?它根本不适合长期运行
不是 bug,是设计如此:schedule 本身只是个“任务调度表”,没有后台线程或事件循环支撑。调用 schedule.run_pending() 后不持续轮询,任务就永远不会执行;而手动写 while True 又容易被信号中断、无法优雅退出、阻塞主线程。
常见错误现象:main() 执行完程序直接退出,或者加了 time.sleep(1) 却发现日志不输出、CPU 占用飙高、Ctrl+C 杀不死进程。
- 只在脚本末尾调一次
schedule.run_pending()→ 任务根本不会触发 - 用
while True: schedule.run_pending(); time.sleep(1)→ 没做异常捕获,KeyboardInterrupt或网络超时可能让整个循环崩掉 - 把它塞进 Flask/FastAPI 的请求处理函数里 → 每次请求都新建调度器,内存泄漏+任务重复注册
APScheduler 是生产环境的默认选择,但别乱用 BackgroundScheduler
APScheduler 确实能扛住长时间运行,但它的 BackgroundScheduler 默认使用 ThreadPoolExecutor,所有 job 都在后台线程跑 —— 这意味着:全局解释器锁(GIL)没被绕过,CPU 密集型任务依然串行;更关键的是,如果主线程因未捕获异常退出,后台线程会被强制终止,job 就悄无声息地丢了。
使用场景:I/O 密集型任务(如调 API、查数据库、发邮件)没问题;需要稳定驻留、支持持久化、可远程管理的定时任务也推荐它。
立即学习“Python免费学习笔记(深入)”;
- 必须显式调用
scheduler.start(),否则什么都不会发生 - 别在 Jupyter 或交互式 Python 里直接 run,容易卡死 —— 它依赖主线程存活
- 想避免意外退出?用
try/except KeyboardInterrupt包住scheduler.start(),并在finally里调scheduler.shutdown() - 需要跨重启保留任务状态?换
SQLAlchemyJobStore,别用默认的内存存储
asyncio + aioschedule 适合异步服务,但和普通 time.sleep 不兼容
如果你的主程序已经是 async def main() + asyncio.run(main()) 结构,那 aioschedule 是轻量又自然的选择。但它完全基于 asyncio,所有 job 函数必须是 async def,且不能出现同步阻塞调用(比如 time.sleep(5)),否则整个 event loop 就卡住。
基于HTML5的图片裁剪插件,所见即所得的裁剪方式,可生成多张缩略图大小图片,基于HTML5 canvas 绘图实现,支持各种效果的裁剪,当然你如果需要保存图片还是需要后端服务程序裁剪图片,裁剪页面是基于Bootstrap框架实现。
常见错误现象:任务注册了,但永远不执行;或者执行一次后就停住;控制台报 RuntimeWarning: coroutine 'xxx' was never awaited。
- job 函数必须用
async def定义,哪怕里面只有一行print() - 替换
time.sleep()→ 改用await asyncio.sleep(5) -
aioschedule.run_pending()必须放进asyncio.create_task()或作为 task 被asyncio.gather()管理,不能裸跑 - 别混用
threading.Timer或schedule—— 多个调度器抢 event loop,行为不可预测
Cron + systemd 是 Linux 服务器最稳的组合,Python 脚本得自己管日志和错误
在服务器上跑定时任务,cron 不是过时方案,而是经过几十年验证的可靠基座。它不依赖 Python 进程存活,不受 GIL 影响,还能自动重试、限制资源、精确到分钟级。但代价是:Python 脚本得自己处理异常、记录日志、避免并发冲突。
典型坑点:脚本在 cron 下跑通,手动执行却报错;或者两个实例同时跑,导致数据错乱。
- 务必在 crontab 里指定完整路径:
/usr/bin/python3 /home/user/tasks/backup.py,别用python或相对路径 - 环境变量不同 —— cron 默认只有 minimal PATH,缺
PYTHONPATH或虚拟环境路径?在 crontab 开头加PATH=...或脚本开头用source venv/bin/activate - 加文件锁防重复:用
os.open(..., os.O_CREAT | os.O_EXCL)尝试创建锁文件,失败就直接 exit - stderr 默认被 mail 给 root,加
> /var/log/mytask.log 2>&1把输出落地,不然出错了你根本不知道
真正难的从来不是“怎么让代码每 5 分钟跑一次”,而是“它挂了有没有人知道”“上次失败的数据会不会被下次覆盖”“换服务器时配置能不能一键迁移”。这些细节,比选哪个库重要得多。









