Python多线程场景下如何保证job1始终先于job2执行?
线程固定优先级调度实现方案
问题现状
现有初始代码如下:
#threads import threading lock = threading.Lock() t1 = threading.Thread(target=job1, args = (lock, )).start() t2 = threading.Thread(target=job2, args = (lock, )).start()
两个线程启动后调度规则如下:
- job1:每10秒递归重调度,单次执行耗时不足1秒,要求优先执行
- job2:每60秒递归重调度,单次执行耗时4-5秒,优先级低于job1
普通互斥锁threading.Lock采用平等竞争机制,无法保证调度触发时job1一定先拿到执行权,存在执行顺序随机的问题。
可选落地方案
按可靠性从高到低排序:
方案1:单线程轮询调度(零竞争,100%保序)
如果业务不强制要求两个任务跑在独立线程,这个方案成本最低、可靠性最高,从调度逻辑上彻底消除竞争:
整个调度逻辑跑在单线程循环里,每次轮询先检查高优先级job1的触发条件,执行完job1再检查低优先级job2的触发条件,从根上避免抢锁乱序问题。
示例代码:
import time last_run_job1 = 0 last_run_job2 = 0 INTERVAL_JOB1 = 10 INTERVAL_JOB2 = 60 while True: current_ts = time.time() # 优先处理高优先级job1 if current_ts - last_run_job1 >= INTERVAL_JOB1: job1() last_run_job1 = current_ts # job1处理完成后再检查job2 if current_ts - last_run_job2 >= INTERVAL_JOB2: job2() last_run_job2 = current_ts # 降低空轮询CPU占用 time.sleep(0.1)
该方案完全适配当前任务耗时场景:两个任务单次执行总耗时不超过6秒,远小于job1的10秒调度间隔,不会出现任务堆积。
方案2:基于条件变量的优先级锁(多线程场景适用)
如果必须保留两个独立线程的架构,替换普通互斥锁为条件变量+待执行计数机制,主动让低优先级任务在高优先级任务待执行时让出执行权:
- 维护
job1_pending计数器记录待执行的job1数量 - job1触发时先计数+1,执行完成后计数-1并通知所有等待线程
- job2执行前必须循环检查计数器,确认无待执行job1时才可以进入执行逻辑
示例代码:
import threading import time cond = threading.Condition() job1_pending = 0 def job1(): global job1_pending # 标记job1待执行 with cond: job1_pending += 1 try: # 此处写入job1实际业务逻辑 time.sleep(0.8) # 模拟单次执行不足1秒 finally: # 执行完成后清除标记,通知等待线程 with cond: job1_pending -= 1 cond.notify_all() # 10秒递归重调度 threading.Timer(10, job1).start() def job2(): global job1_pending # 等待所有待执行job1跑完再拿执行权 with cond: while job1_pending > 0: cond.wait() try: # 此处写入job2实际业务逻辑 time.sleep(4.5) # 模拟单次执行4-5秒 finally: pass # 60秒递归重调度 threading.Timer(60, job2).start() # 启动任务 job1() job2()
如果需要job2执行中途也能被job1抢占,可以把job2的长任务拆分为多个小执行步,每步执行前检查job1_pending状态,存在待执行job1时主动保存执行上下文并让出锁,等job1执行完成后再恢复job2的执行。
方案3:系统级线程优先级设置(不推荐,稳定性差)
可以通过操作系统接口调整两个线程的调度优先级,将job1绑定的线程优先级设置为高于job2的线程,但该方案存在明显缺陷:
- 跨平台兼容性差:Windows、Linux、macOS的线程优先级设置接口不统一
- 受Python GIL调度机制影响,无法100%保证用户态业务逻辑的执行顺序,仅适合非核心场景临时使用
避坑说明
普通threading.Lock、threading.RLock都不支持优先级调度,锁竞争时的获取顺序由操作系统调度决定,无法保证高优先级线程一定先拿到锁,不要用这类锁实现优先级控制。
内容的提问来源于stack exchange,提问作者Dasanudasa Krishna Balarama Da
相关产品推荐
相关产品推荐

