在 python 中,我如何 运行 并发生成器循环在其中一个产生时暂停或终止?

in python, how can i run concurrent generator loops that pause or terminate when one of them yields?

我想在一台生产设备上模拟维护过程。这台机器可能由于以下三个原因之一而停机维护,即 (i) 它可能根据 1/MTBF 的指数描述的指数分布概率发生故障,其中 MTBF 是平均故障间隔时间,(ii) 或者它可能最终会按照定义的时间表进行基于时间的服务,例如自上次服务以来的 4、13、26 或 52 周后,其服务会重新设置故障概率以重新开始 (iii) 或者它可能是拆除进行例行检查,并根据检查结果进行任何维修或修复工作,这将再次重置故障指数功能。是否可以设置三个 while True 循环,它们将同时 运行 它们各自的超时函数,但一旦三个进程中的任何一个实际超时,所有循环都会停止?最好在简单的环境中?像...

         
    import simpy
    import random

    mtbf = 150 #hours
    service_interval = 600 #hours
    inspect_repair_interval = 300 #hours


    def run_to_failure():
        while True:
            failed = random.expovariate(1/mtbf)
            yield env.timeout(failed)
        
    def run_to_service():
        while True:
            stopped = service_interval
            yield env.timeout(stopped)
        
    def run_to_repair():
        while True:
            paused = inspect_repair_interval
            yield env.timeout(paused)

现在,我如何 运行 所有 3 个功能同时运行,但能够在其中任何一个产生时停止并重置所有功能?产生的值将作为后续过程的输入,这些后续过程中的哪一个 运行 也取决于哪个函数产生了值

这里是一个机器同时有三个进程运行的例子:主机任务,定期维护的循环,故障事件

"""
quick sim of a machine with breakdowns

programmer: Michael R. Gibbs
"""

import simpy
import random

class Machine():
    """
    A machine with a main processing loop that can be
    interupted with breakdowns
    """

    def __init__(self, env):
        """
        Initializes the machine and starts
        processing and breadowns
        """

        self.env = env

        # start main task
        self.startup()

        # start schedule for service
        self.service = self.env.process(self.wait_for_service())

    def startup(self):
        """
        Starts up the machine
        Also starts up the breakdown schedule
        """
        self.task = self.env.process(self.main_task())
        self.breakdown = self.env.process(self.wait_for_breakdown())

    def shut_down(self):
        """
        Shuts down the machine
        Also kills the pending breakdown
        """
        
        if self.task is not None:
            # only shutdown if not running
            self.task.interrupt()
            self.task = None


        if self.breakdown is not None:
            # only cancel pending breakdown if it is still pending
            self.breakdown.interrupt()

    def main_task(self):
        """
        The main processing loop of the machine
        """

        print(f'{self.env.now} - starting up machine')

        try:
            while True:
                yield self.env.timeout(3)
                print(f'{self.env.now} - did some work')
        except simpy.Interrupt as i:
            print(f'{self.env.now} - processing has been interupted')

        print(f'{self.env.now} - shutting down machine')

    def wait_for_service(self):
        """
        Schedules and executes maintaince 

        runs on a loop
        breakdowns do not delay maintenance schedule
        """
        while True:
            yield self.env.timeout(21)
            # time for maintenance
            print(f'{self.env.now} - time for service')

            if self.task is None:
                # already processing a breakdown
                print( "-------already shutdown ")

            else:
                self.shut_down()

                # do maintenance
                yield self.env.timeout(2)
                print(f'{self.env.now} - finished service')

                # restart machaine
                self.startup()

    def wait_for_breakdown(self):
        """
        Creates a one time breakdown
        """

        print(f'{self.env.now} - breakdow clock started')

        try:

            yield self.env.timeout(random.randint(4,10))
            # time for a breakdown

            self.breakdown = None

            print(f'{self.env.now} - breakdown')

            # shutdown and fix machine
            self.shut_down()

            yield self.env.timeout(7)

            # machine fixed, start it back up
            print(f'{self.env.now} - breakdow fixed')

            self.startup()
        except simpy.Interrupt as i:
            print(f'{self.env.now} - breakdow clock stopped')



env = simpy.Environment()
machine = Machine(env)
env.run(100)