基于患者失约率的预约调度Python代码死循环问题排查修复
门诊预约调度系统死循环故障排查与修复
程序死循环的核心诱因是while trial <= 1循环存在未覆盖的退出分支,当患者无匹配可约时隙时,循环控制变量trial始终不更新,参数规模越大触发该分支的概率越高。具体故障点和修复方案如下:
具体故障点
- 逻辑运算符误用:使用位运算符
&代替逻辑与运算符and,运算符优先级差异导致条件判断逻辑完全错乱,例如noshowtype[p] == 0 & count ==0实际执行顺序为noshowtype[p] == (0 & count) == 0,和预期判断逻辑不符。 - 无退出兜底逻辑:当患者偏好医生的号源全部约满、或患者自身无任何可用时隙时,四个调度分支都不会修改
trial值使其满足循环退出条件,程序永久卡在当前循环。 - 负载统计错误:统计医生已接诊量时硬编码索引
PHY-1,始终只统计最后一位医生的排班数据,无偏好患者的医生分配逻辑完全失效,号源分配极不均衡,更快触发号源占满的死循环场景。 - 超约计数错误:超约计数同样硬编码指向最后一位医生,未和当前分配的医生绑定,预设的单医生单时隙超约上限校验完全不生效。
- 时隙遍历逻辑错误:查找可用时隙时,只要第一个时隙患者不可用就直接break终止遍历,不会检查后续时隙,大量患者被错误判定为无法预约。
修复后完整代码
import pandas as pd import numpy as np import random import datetime SLOT = 12 # 每日时隙总数 PHY = 2 # 医生总数 P = 36 # 患者总数 number_OB = np.zeros((PHY, 1)) # 各医生超约数量 Limit_OB = np.zeros((PHY, 1)) for i in range(Limit_OB.shape[0]): Limit_OB[i] = 2 # 单医生单时隙最大接诊2名患者 # 患者偏好:1=偏好医生1,2=偏好医生2,3=无偏好 preference = [random.randint(1, 3) for i in range(P)] # 失约类型:0=低失约风险,1=高失约风险 noshowtype = [random.randint(0, 1) for i in range(P)] # 患者时隙可用矩阵:1=对应时隙可就诊,0=不可就诊 availability = np.random.randint(2, size=(P, SLOT)) # 变量初始化 totpat = np.zeros((PHY, SLOT)) # 各医生各时隙已预约患者数 assign = np.zeros(shape=(P, SLOT, PHY)) # 患者预约结果标记 totpatslot = [0]*SLOT # 各时隙总预约人数 noapp = np.zeros((P, 1)) # 患者未预约标记 put = np.zeros((P, SLOT)) # 患者时隙分配标记 unschedule = np.zeros((P, SLOT)) # 时隙不可约标记 slotcap = [2,1,1,1,2,1,1,1,2,1,1,1] # 各时隙容量上限 for p in range(P): count = 0 # 处理无偏好患者,分配到当前预约量更少的医生 if preference[p] == 3: tot_pat_sch = [0,0] for phy in range(PHY): for s in range(SLOT): tot_pat_sch[phy] += totpat[phy, s] if tot_pat_sch[0] < tot_pat_sch[1]: preference[p] = 1 elif tot_pat_sch[1] < tot_pat_sch[0]: preference[p] = 2 else: preference[p] = random.randint(1, 2) trial = 0 selected_phy = preference[p] - 1 while trial <= 1: # 低失约风险患者优先分配空时隙 if noshowtype[p] == 0 and count == 0: for s in range(SLOT): if totpat[selected_phy, s] == 0 and availability[p, s] == 1: assign[p, s, selected_phy] = 1 put[p, s] = 1 count = 1 trial = 2 totpat[selected_phy, s] += 1 totpatslot[s] += 1 break # 高失约风险患者优先分配空时隙 if noshowtype[p] == 1 and count == 0: for s in range(SLOT): if totpat[selected_phy, s] == 0 and availability[p, s] == 1: assign[p, s, selected_phy] = 1 put[p, s] = 1 count = 1 trial = 2 totpat[selected_phy, s] += 1 totpatslot[s] += 1 break # 无空时隙时分配到有余量的超约时隙 if count == 0: has_slot = False for s in range(SLOT): if totpat[selected_phy, s] < slotcap[s] and availability[p, s] == 1: assign[p, s, selected_phy] = 1 number_OB[selected_phy] += 1 put[p, s] = 1 count = 1 trial = 2 totpat[selected_phy, s] += 1 totpatslot[s] += 1 has_slot = True break # 遍历完所有时隙都无可用号,标记为未预约 if not has_slot: noapp[p] = 1 for s in range(SLOT): if availability[p,s] == 0: unschedule[p,s] = 1 trial = 2 # 兜底计数,避免异常分支死循环 if count == 0: trial += 1
修复说明
- 所有位运算符
&替换为逻辑运算符and,修正条件判断逻辑 - 修正医生负载、超约计数的索引错误,确保统计数据和目标医生对应
- 补全无可用时隙时的兜底逻辑,遍历完所有时隙仍无空位直接标记患者未预约,更新循环变量退出
- 修正时隙遍历的错误break逻辑,遍历完所有时隙后再判定是否可约,避免漏判可用空位
- 优化无偏好患者的医生分配逻辑,不再随机分配,优先选择负载更低的医生平衡号源占用
内容的提问来源于stack exchange,提问作者Ali Kasaie
相关产品推荐
相关产品推荐

