【问题标题】:Simpy Container Questions简单的容器问题
【发布时间】:2022-01-16 13:23:00
【问题描述】:

全面披露:我是一名学生,可能搞砸了一些约定、符号和最佳实践。我热烈欢迎反馈。

我正在尝试实现 SimPy 文档中的加油站示例版本,附在此处:

Covers:

- Resources: Resource
- Resources: Container
- Waiting for other processes

Scenario:
  A gas station has a limited number of gas pumps that share a common
  fuel reservoir. Cars randomly arrive at the gas station, request one
  of the fuel pumps and start refueling from that reservoir.

  A gas station control process observes the gas station's fuel level
  and calls a tank truck for refueling if the station's level drops
  below a threshold.


import itertools
import random

import simpy


RANDOM_SEED = 42
GAS_STATION_SIZE = 200     # liters
THRESHOLD = 10             # Threshold for calling the tank truck (in %)
FUEL_TANK_SIZE = 50        # liters
FUEL_TANK_LEVEL = [5, 25]  # Min/max levels of fuel tanks (in liters)
REFUELING_SPEED = 2        # liters / second
TANK_TRUCK_TIME = 300      # Seconds it takes the tank truck to arrive
T_INTER = [30, 300]        # Create a car every [min, max] seconds
SIM_TIME = 1000            # Simulation time in seconds


def car(name, env, gas_station, fuel_pump):
    """A car arrives at the gas station for refueling.

    It requests one of the gas station's fuel pumps and tries to get the
    desired amount of gas from it. If the stations reservoir is
    depleted, the car has to wait for the tank truck to arrive.

    """
    fuel_tank_level = random.randint(*FUEL_TANK_LEVEL)
    print('%s arriving at gas station at %.1f' % (name, env.now))
    with gas_station.request() as req:
        start = env.now
        # Request one of the gas pumps
        yield req

        # Get the required amount of fuel
        liters_required = FUEL_TANK_SIZE - fuel_tank_level
        yield fuel_pump.get(liters_required)

        # The "actual" refueling process takes some time
        yield env.timeout(liters_required / REFUELING_SPEED)

        print('%s finished refueling in %.1f seconds.' % (name,
                                                          env.now - start))


def gas_station_control(env, fuel_pump):
    """Periodically check the level of the *fuel_pump* and call the tank
    truck if the level falls below a threshold."""
    while True:
        if fuel_pump.level / fuel_pump.capacity * 100 < THRESHOLD:
            # We need to call the tank truck now!
            print('Calling tank truck at %d' % env.now)
            # Wait for the tank truck to arrive and refuel the station
            yield env.process(tank_truck(env, fuel_pump))

        yield env.timeout(10)  # Check every 10 seconds


def tank_truck(env, fuel_pump):
    """Arrives at the gas station after a certain delay and refuels it."""
    yield env.timeout(TANK_TRUCK_TIME)
    print('Tank truck arriving at time %d' % env.now)
    amount = fuel_pump.capacity - fuel_pump.level
    print('Tank truck refuelling %.1f liters.' % amount)
    yield fuel_pump.put(amount)


def car_generator(env, gas_station, fuel_pump):
    """Generate new cars that arrive at the gas station."""
    for i in itertools.count():
        yield env.timeout(random.randint(*T_INTER))
        env.process(car('Car %d' % i, env, gas_station, fuel_pump))


# Setup and start the simulation
print('Gas Station refuelling')
random.seed(RANDOM_SEED)

# Create environment and start processes
env = simpy.Environment()
gas_station = simpy.Resource(env, 2)
fuel_pump = simpy.Container(env, GAS_STATION_SIZE, init=GAS_STATION_SIZE)
env.process(gas_station_control(env, fuel_pump))
env.process(car_generator(env, gas_station, fuel_pump))

# Execute!
env.run(until=SIM_TIME)

我最大的挫败感是尝试采用某种方式将容器让给油罐车,这样在加油站(通过油罐车)补充其气体库存时,没有汽车可以加油。我尝试在汽车定义中添加 if 语句,以在 gas_station_control 条件中的循环被触发但未成功时检查加油站燃料库存的状态或产生资源。

我的情况是: 在设定的时间范围内有 3 辆随机汽车。加油站的容量是1.5罐汽油,一辆汽车抽一个负荷需要3个小时。一旦那辆车离开,我需要重新填充我的加油站储液罐,这需要 4 小时(如果液位 = 0.5 @ 0.25 负载/小时的速率,则需要 6 小时才能填充所有 1.5 个油箱)。我还需要确保如果队列中当前没有汽车在等待,我应该重新填充水库,不管我是否超出了汽车可能会停下来的当前时间范围。我需要确保记录每辆车在队列中等待的时间。

【问题讨论】:

  • 这只是在补充燃油时延迟,但同时仍允许汽车从油箱中拉出。他们共享容器,所以我倾向于认为这与汽车的定义有关。
  • 加油站不控制对集装箱的访问吗?因此,如果您希望加油车完全控制集装箱,则必须首先占用两个加油站资源。我会从这个开始,但如果您不希望卡车等待完全访问,您可以使用中断或优先资源队列

标签: python simulation simpy


【解决方案1】:

我仍然不确定你想做什么。为什么卡车在补货时,汽车没有待处理的请求?这些请求不会阻止卡车添加到容器中。

无论如何,我尝试了一下,这就是我的想法

在这个版本中,当汽车到达加油站时,它会检查容器是否有足够的汽油来给汽车加油。如果是这样,它将发出容器请求。如果没有,它将等待卡车到达并为加油站加油,然后提出集装箱请求。汽车知道补货何时完成,因为我在gas_station 中添加了一个replep_event,该事件在卡车完成补货时由卡车触发。如果汽车需要等待,它可以屈服于这个事件。请注意,超过一辆车可以在此事件中让步。

"""
Covers:

- Resources: Resource
- Resources: Container
- Waiting for other processes

Scenario:
  A gas station has a limited number of gas pumps that share a common
  fuel reservoir. Cars randomly arrive at the gas station, request one
  of the fuel pumps and start refueling from that reservoir.

  A gas station control process observes the gas station's fuel level
  and calls a tank truck for refueling if the station's level drops
  below a threshold.

Updated my Michel R. Gibbs
Car does not make a request for gas amount unless it can get full amount.
If cannot get full amount, will wait for truck to replenish before making request
"""

import itertools
import random

import simpy


RANDOM_SEED = 42
GAS_STATION_SIZE = 200     # liters
THRESHOLD = 10             # Threshold for calling the tank truck (in %)
FUEL_TANK_SIZE = 50        # liters
FUEL_TANK_LEVEL = [5, 25]  # Min/max levels of fuel tanks (in liters)
REFUELING_SPEED = 2        # liters / second
TANK_TRUCK_TIME = 300      # Seconds it takes the tank truck to arrive
T_INTER = [30, 300]        # Create a car every [min, max] seconds
SIM_TIME = 2000            # Simulation time in seconds
REPLENISHMENT_SPEED = 20   # linters / second for tanker truck to refill gas staiion


def car(name, env, gas_station, fuel_pump, replenish_event):
    """A car arrives at the gas station for refueling.

    It requests one of the gas station's fuel pumps and tries to get the
    desired amount of gas from it. If the stations reservoir is
    depleted, the car has to wait for the tank truck to arrive.

    """
    fuel_tank_level = random.randint(*FUEL_TANK_LEVEL)
    print('%s arriving at gas station at %.1f' % (name, env.now))
    with gas_station.request() as req:
        start = env.now
        # Request one of the gas pumps
        yield req
        print('%s exit queue and started pumping gas at %.1f' % (name, env.now))
        # Get the required amount of fuel
        liters_required = FUEL_TANK_SIZE - fuel_tank_level
        
        # check if amount is available
        while liters_required > fuel_pump.level:
            # use a while in case another car uses up the replenishment

            # wait for truck
            print('%s waiting for fuel truck before starting to pump %.1f' % (name, env.now))
            yield replenish_event

        yield fuel_pump.get(liters_required)

        # The "actual" refueling process takes some time
        yield env.timeout(liters_required / REFUELING_SPEED)

        print('%s finished refueling in %.1f seconds.' % (name,
                                                          env.now - start))


def gas_station_control(env, gas_station, fuel_pump):
    """
    Periodically check the level of the *fuel_pump* and call the tank
    truck if the level falls below a threshold.
    """
    
    gas_station.replenish_event = env.event()
    while True:
        if fuel_pump.level / fuel_pump.capacity * 100 < THRESHOLD:
            # We need to call the tank truck now!
            print('Calling tank truck at %d' % env.now)
            env.process(tank_truck(env, fuel_pump, gas_station.replenish_event))

            # yield until replenishment is finished
            yield gas_station.replenish_event

            # reset event for next replenishment
            gas_station.replenish_event = env.event()

        yield env.timeout(10)  # Check every 10 seconds


def tank_truck(env, fuel_pump, replenish_event):
    """
    Arrives at the gas station after a certain delay and refuels it.
    """
    yield env.timeout(TANK_TRUCK_TIME)
    print('Tank truck arriving at time %d' % env.now)
    
    amount = fuel_pump.capacity - fuel_pump.level
    replem_time = amount / REPLENISHMENT_SPEED
    yield env.timeout(replem_time)

    print('Tank truck replenshied %.1f liters at time %.1f.' % (amount, env.now))
    yield fuel_pump.put(amount)

    # let any listeners know replenishment is done
    replenish_event.succeed()


def car_generator(env, gas_station, fuel_pump):
    """
    Generate new cars that arrive at the gas station.
    """
    for i in itertools.count():
        yield env.timeout(random.randint(*T_INTER))
        env.process(car('Car %d' % i, env, gas_station, fuel_pump, gas_station.replenish_event))


# Setup and start the simulation
print('Gas Station refuelling')
random.seed(RANDOM_SEED)

# Create environment and start processes
env = simpy.Environment()
gas_station = simpy.Resource(env, 2)
fuel_pump = simpy.Container(env, GAS_STATION_SIZE, init=GAS_STATION_SIZE)
env.process(gas_station_control(env, gas_station, fuel_pump))
env.process(car_generator(env, gas_station, fuel_pump))

# Execute!
env.run(until=SIM_TIME)

【讨论】:

  • 谢谢迈克尔!这很棒,非常接近我最终目标所需要的。实际上,我最终在没有 SimPy 库的情况下直接使用 python 对其进行了编程。就我的目的而言,是否使用 SimPy 之间存在一定的权衡。在 Python 中,在指定的时间窗口中安排“随机”到达很容易,而在 SimPy 中则涉及更多。这是对库和离散时间模拟的一个很好的介绍,你可以在这里找到我的实际问题提示:mathmodels.org/Problems/1993/MCM-A/1993A.pdf
  • 听起来更像是一个优化问题。 Python 有一个名为 Pulp 的优化包,但这不是一个简单的问题
  • 我的解决方案可以在github.com/jdellag/coaltipple找到,如果你想看看
猜你喜欢
  • 1970-01-01
  • 2011-03-17
  • 2013-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-03
  • 2010-10-21
相关资源
最近更新 更多