Proceso de simulación - no puede utilizar el método de envío del generador?

Antecedentes

Se dice que el proceso de SimPy es un generador en el documento, que esperaba tener el Enviar método como en PEP 342.

Los procesos son descritos por Python simple generadores. Puede llamarlos función de proceso o método de proceso, dependiendo de si es una función o método normal de una clase. Durante su vida, crean eventos y los rinden para esperar a que sean disparados.

Puedo usar Enviar enviar un mensaje a un generador de otro, por ejemplo para inyectar un generador de estación de carga en el generador ev.

from typing import Dict, Optional, Generator
import time

def ev(env) -> Generator:
    while True:
        next_charging_station = yield
        print("next_charging_station[{}]".format(next_charging_station))
        
def dispathcer(env, ev) -> Generator:
    while True:
        time.sleep(3)
        print('Dispatching the next charging station')
        ev.send("new station")
        
process_ev = ev(env)
next(process_ev)

process_dispatcher = dispathcer(env, process_ev)
Dispatching the next charging station
next_charging_station[new station]
Dispatching the next charging station
next_charging_station[new station]

Sin embargo, el proceso SymPy no tiene el Enviar método.

import simpy
env = simpy.Environment()
                    
def ev(env):
    while True:
        next_charging_station = yield
        print("next_charging_station[{}]".format(next_charging_station))
        
def dispathcer(env, ev):
    while True:
        print('Dispatching the next charging station at %d' % (env.now))
        ev.send("new station")

rocess_ev = env.process(ev(env))
process_dispatcher = env.process(dispathcer(env, process_ev))
-----

Dispatching the next charging station at 0
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
 in 
      1 process_ev = env.process(ev(env))
----> 2 process_dispatcher = env.process(dispathcer(env, process_ev))

 in dispathcer(env, ev)
     11     while True:
     12         print('Dispatching the next charging station at %d' % (env.now))
---> 13         ev.send("hoge")

AttributeError: 'Process' object has no attribute 'send'

Pregunta

Por favor, ayuda a entender la razón de este error si esto es como diseñado (enviar y posiblemente cerrar /throw no están disponibles) o si malinterpreté algo. Supongo que todas las sincronizaciones deben ser hechas por el entorno SimPy a través de sus eventos, de lo contrario el medio ambiente puede perder la pista de los estados de procesos, pero no seguro.

Por favor aconseje si hay una manera de actualizar la memoria en un proceso de otro. Por ejemplo, cómo puedo cambiar el código para inyectar dinámicamente un proceso de estación de carga en el proceso ev.

import simpy
env = simpy.Environment()

def charging_station(env):
    print('Start charging at %d' % (env.now))
    charge_duration = 3
    yield env.timeout(charge_duration)
    return
                    
def ev(env):
    while True:
        print('Start driving at %d' % (env.now))
        driving_duration = 5
        yield env.timeout(driving_duration)

        print('Stop at a charging station at %d' % (env.now))

        # [Q] Instead of creating a charging process inside the ev process,
        # how to get it injected?
        yield env.process(charging_station(env))    # <----- 

env.process(ev(env))
env.run(until=20)

-----
Start driving at 0
Stop at a charging station at 5
Start charging at 5
Start driving at 8
Stop at a charging station at 13
Start charging at 13
Start driving at 16

Por ejemplo, algo así si es posible.

def new_ev(env): # <---- how to implement?
    while True:
        next_charging_station = yield   # Get the next station process
        print('Start charging at %d' % (env.now))
        yield next_charging_station

        print('Start driving at %d' % (env.now))
        driving_duration = 5
        yield env.timeout(driving_duration)

Se ve la inyección en un proceso puede ser posible sólo en su creación. Por lo tanto, una manera puede inyectar al despachador en el proceso ev, y luego obtener una estación de carga desde el interior del proceso ev. Sin embargo, quisiera inyectar explícitamente cualquier caso en él en lugar de tirar de dentro.

import random
import simpy
env = simpy.Environment()

class Dispatcher(object):
    env = None
    def __init__(self, env):
        self.env = env
        print('Start dispatcher at time %d' % self.env.now)
        
        # Start the run process everytime an instance is created.
        #self.process = env.process(self.run())

    def run(self):
        while True:
            print('Start dispatcher at time %d' % self.env.now)
            yield self.env.timeout(1)
            
    def next_charger_station(self):
        return self._charge(random.randint(1, 1000), self.env)

    def _charge(self, id, env):
        print('station %s start charging at time %d' % (id, env.now))
        yield env.timeout(5)
        return

                    
def ev(env, dispatcher):
    while True:        
        print('EV stops at the new charging station at time %d' % (env.now))
        yield env.process(dispatcher.next_charger_station())
        
        print('EV start driving from the charging station at time %d' % (env.now))
        yield env.timeout(5)
            

dispatcher = Dispatcher(env)
process_ev = env.process(ev(env, dispatcher))
env.run(until=30)

Pregunta hecha hace 3 años, 4 meses, 29 días - Por techscribe


2 Respuestas:

  • El error que estás experimentando se debe a que SimPy no proporciona un método send en los procesos de la misma manera que se hace en los generadores estándar de Python. En SimPy, los procesos se manejan de manera diferente y no tienen la capacidad de enviar mensajes entre ellos directamente.

    En su lugar, en SimPy se utilizan los eventos y las señales para sincronizar y comunicar entre los distintos procesos. Para lograr el mismo efecto que estás intentando con el método send en un generador estándar de Python, puedes utilizar los eventos y señales de SimPy para coordinar la ejecución de los procesos.

    Para actualizar la memoria en un proceso desde otro en SimPy, puedes utilizar las siguientes estrategias:

    • Utilizar eventos de SimPy: Puedes utilizar eventos de SimPy para señalar el estado o enviar información entre procesos. Por ejemplo, puedes usar `Event` para indicar cuando una estación de carga está disponible y luego hacer que el proceso ev lo maneje.
    • Comunicación a través del entorno: Puedes utilizar las variables del entorno `env` para almacenar y compartir información entre los diferentes procesos.

    Aquí te dejo un ejemplo modificado de tu código donde se utiliza un evento para señalar cuando una estación de carga está disponible y el proceso ev lo maneja:

    python
    import simpy
    
    env = simpy.Environment()
    charging_station_event = env.event()
    
    def charging_station(env):
        print('Start charging at %d' % (env.now))
        charge_duration = 3
        yield env.timeout(charge_duration)
        charging_station_event.succeed('new station')
    
    def ev(env):
        while True:
            print('Start driving at %d' % (env.now))
            driving_duration = 5
            yield env.timeout(driving_duration)
    
            print('Stop at a charging station at %d' % (env.now))
            yield charging_station_event
    
    env.process(charging_station(env))
    env.process(ev(env))
    env.run(until=20)
    

    En este ejemplo, el charging_station proceso activa un evento cuando una nueva estación de carga está disponible. El ev proceso espera a que este evento se active antes de continuar con su ejecución.

    Espero que esta explicación te ayude a comprender cómo abordar la comunicación entre procesos en SimPy. Si tienes alguna otra pregunta, no dudes en hacerla. ¡Estoy aquí para ayudarte!

    Respondida el Dec 18, 2020 a las 07:52 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Explicación del error

    Los procesos de SimPy no tienen un método send porque no son generadores mejorados como se define en PEP 342. SimPy utiliza su propio mecanismo de programación concurrente basado en eventos en su lugar.

    Actualización del estado desde otro proceso

    Para actualizar el estado desde otro proceso, puedes utilizar eventos de SimPy. Los eventos son objetos que representan acciones que ocurren en el futuro. Puedes programar un evento usando el método env.event() y luego esperar a que ocurra usando yield env.event().

    Aquí tienes un ejemplo modificado de tu código que usa eventos para inyectar dinámicamente un proceso de estación de carga:

    python
    import simpy
    env = simpy.Environment()
    
    def charging_station(env, name):
        print(f'Start charging at {env.now} - {name}')
        yield env.timeout(3)
        return
    
    def ev(env, dispatcher):
        while True:
            print(f'Start driving at {env.now}')
            yield env.timeout(5)
    
            print(f'Stop at a charging station at {env.now}')
    
            

    Crea un evento para inyectar un proceso de estación de carga

    new_station_event = env.event()

    Programa un evento para disparar después de 1 segundo

    env.process(dispatcher.next_charger_station(new_station_event))

    Espera a que se dispare el evento

    yield new_station_event

    Inicia el proceso de la estación de carga

    yield env.process(charging_station(env, new_station_event.value)) class Dispatcher(object): env = None def __init__(self, env): self.env = env def next_charger_station(self, event):

    Genera un nombre aleatorio para la estación de carga

    name = random.randint(1, 1000)

    Programa el evento para disparar cuando la estación de carga esté lista

    env.process(self._charge(name, event)) def _charge(self, name, event): yield env.timeout(5) event.succeed(name) dispatcher = Dispatcher(env) process_ev = env.process(ev(env, dispatcher)) env.run(until=30)

    Inyección explícita de procesos

    Sí, la inyección explícita de procesos es posible creando un nuevo proceso dentro del proceso existente y luego usando yield para esperar a que se complete. Sin embargo, esto solo se puede hacer durante la creación del proceso. No puedes inyectar un proceso en un proceso existente después de que se haya creado.

    Tu código de ejemplo demuestra cómo hacer esto:

    python
    def next_charger_station(self):
        

    Genera un nombre aleatorio para la estación de carga

    name = random.randint(1, 1000)

    Crea un nuevo proceso para representar la estación de carga

    yield env.process(self._charge(name)) return name

    Respondida el Dec 18, 2020 a las 08:01 - por Gemini

    Votos positivos: 0 | Votos negativos: 0