You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Simpy的Python仿真按需创建事件 解决发货超单、流程触发失效问题

核心问题根因定位
  • 第一版代码的运行偏差来自流程顺序错误:5个提前启动的发货进程,把“获取待处理订单”的操作放在了整个发货流程的最后端。流程执行顺序是先打发货日志、算发货参数、模拟运输过程、打配送完成日志,最后才去订单容器里取1个单位的订单。这就导致所有进程哪怕还没拿到有效订单,也会完整跑一遍全流程的日志输出和统计逻辑,最终呈现的发货总量远高于实际到达的订单量。
  • 第二版调整代码失效来自判断时机错误:仅在仿真启动的第0秒执行一次订单数判断,只要启动时刻没有待处理订单,就直接跳过发货进程创建。后续到货流程持续产生的新订单,永远不会触发新的发货流程启动,最终整个发货环节完全停转。
Simpy按需创建事件的核心实现逻辑

依托Simpy内置的事件阻塞特性,就能零冗余实现“订单随到随发、无积压”的目标,不需要手动维护脱离容器状态的计数变量:

  • simpy.Container的get操作本身是自动阻塞事件:执行yield 容器.get(需求数量)时,如果当前容器库存不足,整个进程会自动挂起,直到有新的put操作补充足够库存,才会自动解除阻塞继续运行。这个特性天然适配“有对应待处理订单才触发发货、没订单就等待”的规则。
  • 按需创建进程的触发规则:每次新订单完成入库(执行完orders.put(1)操作)时,自动对比当前待处理订单总量、当前处于等待取单状态的发货进程数,差值大于0时直接新建对应数量的发货进程,保证发货处理能力和待处理订单量完全匹配,无积压、无空跑。
修正后的参考实现代码
class LC:
    def __init__(self, env):
        # 原有统计容器保留,去掉冗余的手动计数变量
        self.dispatch = simpy.Container(env, capacity=100000, init=0)
        self.costs = simpy.Container(env, capacity=100000, init=0)
        self.shipment_count = simpy.Container(env, capacity=10000, init=0)
        self.orders = simpy.Container(env, capacity=10000, init=0)
        # 记录当前处于等待取单状态的发货进程数,用于按需创建时的数量匹配
        self.waiting_ship_proc = 0

def shipping(env, ship):
    # 发货进程第一行就阻塞等待待处理订单,没拿到订单就一直挂起
    yield ship.orders.get(1)
    ship.waiting_ship_proc -=1
    print('Shipment was sent at %d' % (env.now))
    # 拿到订单之后再计算发货参数
    time, weight = get_weight_n_time()
    if weight <=35:
        cost = get_cost(weight,0)
    else:
        cost = get_cost(weight,1)
    yield env.timeout(time)
    print ('Shipment of %d kgs where delivered after %d days with cost of $ %d' %(weight, time, cost))
    # 完成发货后更新统计值
    yield ship.dispatch.put(weight)
    yield ship.costs.put(cost)
    yield ship.shipment_count.put(1)

def arrival(env, ship):
    while True:
        print('Order arrived at %d'%(env.now))
        # 新订单入库
        yield ship.orders.put(1)
        # 按需创建发货进程:如果待处理订单数大于当前等待取单的发货进程数,就补建进程
        pending_orders = ship.orders.level
        need_proc = pending_orders - ship.waiting_ship_proc
        for _ in range(need_proc):
            env.process(shipping(env, ship))
            ship.waiting_ship_proc +=1
        # 按照原有节奏,每1天到1个新订单
        yield env.timeout(1)
        
env = simpy.Environment()
ship = LC(env)
env.process(arrival(env, ship))
env.run(until=100)
关键实现注意事项
  • 必须把“获取待处理订单”的代码放在发货流程的最开头,严禁先执行发货日志打印、参数计算、运输模拟等逻辑再取订单,否则会出现无单空跑的问题。
  • 优先使用simpy.Container自带的.level属性查询实时库存,不要手动维护和容器状态不同步的计数器,避免因事件调度时序偏差导致的计数不准问题。
  • 如果需要保留固定5辆货车的运力配置,只需要在仿真启动时一次性创建5个发货进程,每个进程启动后第一时间执行取订单的阻塞操作,就不会出现空跑发货的问题,不需要每次判断库存再新建进程。

内容的提问来源于stack exchange,提问作者nesquess

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.24 23:27:03