Python SimPyシミュレーションシリーズ(2)

4811 ワード

この記事では、SimPyを使用して2つのシミュレーション要件を解決する方法について説明します.
  • リカバリをいつでも中断する方法Process(プロセス)
  • Resource(リソース)の数
  • を動的に設定する方法
    この2つの要件を満たすシーンは、次のとおりです.
  • シミュレーション中、ある工程が中断する、中断は予め設定された時間又は不確定時間
  • に基づいてもよい.
  • シミュレーションの過程で、人的資源も時間の変化に基づいて、シミュレーションの現実の労働者の勤務手配
  • リソースとプロセスの概念をレビューResourceProcessはSimPyが人的資源とプロセスに対して抽象的な構造である.Resourceは1つのキューのようなもので、その長さは予め設定する資源数であり、異なる工程は時間の前後と与えられた優先度に従ってキューに入る.Processは構造的にはジェネレータであり、send法によりExceptionに伝達するProcessを遮断することができる.
    例えば、ある工程で1人の労働者を占有する必要があり、30 minを費やしてプロセスを完了し、現在呼び出すことができるすべての労働者数は10であり、コード形式は以下の通りである.
    import simpy
    import random
    
    
    WORKERNUM = 10 #    
    PROCESS_TIME = 30 * 60 #     ,        
    MEAN_  = 4 * 60 #         
    
    def process(env, workers, store):
        """  """
        while True:
            with workers.request() as req:
                yield req
                item = yield store.get()
                print(f"{env.now} - {item} - start")
                yield env.timeout(PROCESS_TIME)
                print(f"{env.now} - {item} - done")
    
    def put_item(env, store):
        """            """
        for i in range(100):
            item = f"{i}_item"
            store.put(item)
            yield env.timeout(random.expovariate(1 / MEAN_))
    
    env = simpy.Environment()
    workers = simpy.Resource(env, 10)
    store = simpy.Store(env)
    
    env.process(process(env, workers, store))
    env.process(put_item(env, store))
    env.run()
    
    

    もっと詳しい紹介と資料は以前の文章Python SimPyシミュレーションシリーズ(1)を振り返ることができる.Processプロセスの動的調整
    次の2つのシナリオがあります.
  • プロセスは随時中断し、
  • を回復する.
  • スケジュールに従ってプロセスを開始または終了する
  • .
    一つのことを区別するには、中断するときに現在のプロセスを完了させてから中断するか、すぐに中断するかを区別します.具体的なシーンは、労働者が現在の職場から異動されたことを想像することができ、彼はまず手元の工程を完成しなければならないか、あるいは手元の仕事を止めて職場を離れる必要がある.
    プロセスの随時中断を実現しなければならない場合、process.interrupt()を通じてprocess、すなわち第1のシーンを中断するしかない.割り込みがスケジュール通りに行うと、第2のシーンでは、複数の異なる時間に開くプロセスを構築してシミュレーションを行うことができる.
    プロセス中断の実装
    from simpy import interrupt, Environment
    
    env = Environment()
    
    def interrupter(env, victim_proc):
        yield env.timeout(1)
        victim_proc.interrupt('Spam')
    
    def victim(env):
        try:
            yield env.timeout(10)
         except Interrupt as interrupt:
             cause = interrupt.cause
    

    マルチセグメントプロセスシミュレーション時間別スイッチ
    
    import simpy
    
    PROCESS_TIME = 3
    
    def put_item(env, store):
        for i in range(20):
            yield env.timeout(0.5)
            store.put(f"{i}_item")
    
    def process(i, env, store, start, end):
    
        yield env.timeout(start)
        while True:
            item = yield store.get()
            #    item                
            if env.now > end:
                print(f"{env.now} - process {i} - end")
                store.put(item)
                env.exit()
            else:
                print(f"{env.now} - {item} - start")
                yield env.timeout(PROCESS_TIME)
                print(f"{env.now} - {item} - end")
    
    env = simpy.Environment()
    store = simpy.Store(env)
    
    env.process(put_item(env, store))
    
    for i, (start, end) in enumerate([(20, 30), (40, 50), (60, 90)]):
        env.process(process(i, env, store, start, end))
    
    env.run()
    
    Resourceリソースの動的調整
  • リソース人数指定されたレイアウトに従って
  • をプロビジョニングResourceは実例化後、修正できないためである.シミュレーションの過程で資源を修正することを満たすために、逆方向の構想を用いた.まず、全てのリソース使用例PriorityResourceは、予め調整可能な最大リソース数を設定しておき、リソース数を調整する必要がある場合には、-1の優先度を持つrequestを使用してリソースを占有するが、通常のプロセスのデフォルト優先度は0である.
    このような操作により、リソースの占有プロセスの優先度が高くなり、通常のプロセスで呼び出すことができるリソースの数が次のようになります. = -
    import simpy
    
    PROCESS_TIME = 2
    
    def put_item(env, store):
        for i in range(20):
            yield env.timeout(0.5)
            store.put(f"{i}_item")
    
    def process(env, store, resource):
        while True:
            item = yield store.get()
            with resource.request() as req:
                yield req
                yield env.timeout(PROCESS_TIME)
    
    def set_resource(env, resource, start_time, end_time):
        """    ,         ,
        end_time     np.inf    ,
        simpy        ,    timeout   。
        """
        duration = end_time - start_time
        yield env.timeout(start_time)
        with resource.request(priority=-1) as req:
            yield req
            yield env.timeout(duration)
    
    env = simpy.Environment()
    store = simpy.Store(env)
    res = simpy.PriorityResource(env, 10)
    
    res_time_table = [(10, 20, 5), (20, 30, 6)]
    env.process(put_item(env, store))
    env.process(process(env, store, res))
    
    for start, end, target_num in res_time_table:
        place_holder = 10 - target_num
        for _ in range(place_holder):
            env.process(set_resource(env, res, start, end))
    
    env.run()