SALABIM 如何最小化内存需求

SALABIM how to minimize memory requirements

提问人:Floris Padt 提问时间:11/16/2023 最后编辑:Floris Padt 更新时间:11/18/2023 访问量:64

问:

我正在使用 python 中的 Salabim 包来模拟一些排队理论。Salabim(文档)基于 SimPy,但具有许多扩展和附加功能。 我的大多数问题都可以在几分钟内得到解决,并且对内存的要求最低。

但是,我想扩展模型,并注意到在对一个简单的 M/M/1 排队问题进行 1 小时的模拟后,模拟捕获了大约 32GB。我预计这是由于一些内部监视器捕获了统计数据。我试图停用其中的大部分,但直到现在都没有成功。

- 我错过了什么陈述?
- 我可以更改哪些内容以最大程度地减少内存需求?

请注意,我使用以下代码切换每个类的监控

    def setup(self):
        self.mode.monitor(False)
        self.status.monitor(False) # added 17 nov, salabim team tip

法典

# passivate/activate method
# https://www.salabim.org/manual/Modelling.html#a-bank-example

import salabim as sim


class CarGenerator(sim.Component):
    def setup(self):
        self.mode.monitor(False)
        self.status.monitor(False) # added 17 nov, salabim team tip

    def process(self):
        while True:
            Car()
            self.hold(iat_distr.sample())


class Car(sim.Component):
    def setup(self):
        self.mode.monitor(False)
        self.status.monitor(False) # added 17 nov, salabim team tip

    def process(self):
        self.enter(waitingline)
        for ChargingStation in ChargingStations:
            if ChargingStation.ispassive():
                ChargingStation.activate()
                break  # activate at most one charging station
        self.passivate()


class ChargingStation(sim.Component):
    def setup(self):
        self.mode.monitor(False)
        self.status.monitor(False)  # added 17 nov, salabim team tip

    def process(self):
        while True:
            while len(waitingline) == 0:
                self.passivate()
            self.car = waitingline.pop()
            self.hold(srv_distr.sample())
            self.car.activate()


N_STATION = 1
iat_distr = sim.Exponential(60 / 40)
srv_distr = sim.Exponential(60 / 50)

# https://www.salabim.org/manual/Reference.html#environment
app = sim.App(
    trace=False,  # defines whether to trace or not
    random_seed="*",  # if “*”, a purely random value (based on the current time)
    time_unit="minutes",  # defines the time unit used in the simulation
    name="Charging Station",  # name of the simulation
    do_reset=True,  # defines whether to reset the simulation when the run method is called
    yieldless=True,  # defines whether the simulation is yieldless or not
)

# Instantiate and activate the client generator
CarGenerator(name="Electric Cars Generator")

# Create Queue and set monitor to stats_only
waitingline = sim.Queue(name="Waiting Cars", monitor=False)
waitingline.length_of_stay.monitor(value=True)
waitingline.length_of_stay.reset_monitors(stats_only=True)

# Instantiate the servers, list comprehension but only 1 server
ChargingStations = [ChargingStation() for _ in range(N_STATION)]

# Execute Simulation
app.run(till=sim.inf)

# Print statistics
waitingline.length_of_stay.print_statistics()

环境

我在适用于 Linux 的 Windows 子系统上使用 Ubuntu 22.04 并在 Ubuntu 22.04 上运行(但在纯 Ubuntu 22.04 系统上也会发生同样的情况)'CPython'python version 3.9.18SALABIM version 23.3.11.1

WSL 版本:1.2.5.0 内核版本:5.15.90.1
WSLg 版本:1.0.51
MSRDC 版本:1.2.3770
Direct3D 版本:1.608.2-61064218
DXCore 版本:10.0.25131.1002-220531-1700.rs-onecore-base2-hyp
Windows 版本:10.0.19045.3693

以下 ENV.yml 文件可用于重新创建 conda 环境或检查包版本。

name: mem_salabim
channels:
  - conda-forge
  - nodefaults
dependencies:
  - _libgcc_mutex=0.1=conda_forge
  - _openmp_mutex=4.5=2_gnu
  - anyio=4.0.0=pyhd8ed1ab_0
  - argon2-cffi=23.1.0=pyhd8ed1ab_0
  - argon2-cffi-bindings=21.2.0=py39hd1e30aa_4
  - arrow=1.3.0=pyhd8ed1ab_0
  - asttokens=2.4.1=pyhd8ed1ab_0
  - async-lru=2.0.4=pyhd8ed1ab_0
  - attrs=23.1.0=pyh71513ae_1
  - babel=2.13.1=pyhd8ed1ab_0
  - backports=1.0=pyhd8ed1ab_3
  - backports.functools_lru_cache=1.6.5=pyhd8ed1ab_0
  - beautifulsoup4=4.12.2=pyha770c72_0
  - bleach=6.1.0=pyhd8ed1ab_0
  - brotli-python=1.1.0=py39h3d6467e_1
  - bzip2=1.0.8=hd590300_5
  - ca-certificates=2023.7.22=hbcca054_0
  - cached-property=1.5.2=hd8ed1ab_1
  - cached_property=1.5.2=pyha770c72_1
  - certifi=2023.7.22=pyhd8ed1ab_0
  - cffi=1.16.0=py39h7a31438_0
  - charset-normalizer=3.3.2=pyhd8ed1ab_0
  - comm=0.1.4=pyhd8ed1ab_0
  - debugpy=1.8.0=py39h3d6467e_1
  - decorator=5.1.1=pyhd8ed1ab_0
  - defusedxml=0.7.1=pyhd8ed1ab_0
  - entrypoints=0.4=pyhd8ed1ab_0
  - exceptiongroup=1.1.3=pyhd8ed1ab_0
  - executing=2.0.1=pyhd8ed1ab_0
  - fqdn=1.5.1=pyhd8ed1ab_0
  - greenlet=3.0.1=py39h3d6467e_0
  - idna=3.4=pyhd8ed1ab_0
  - importlib-metadata=6.8.0=pyha770c72_0
  - importlib_metadata=6.8.0=hd8ed1ab_0
  - importlib_resources=6.1.1=pyhd8ed1ab_0
  - ipykernel=6.26.0=pyhf8b6a83_0
  - ipython=8.17.2=pyh41d4057_0
  - isoduration=20.11.0=pyhd8ed1ab_0
  - jedi=0.19.1=pyhd8ed1ab_0
  - jinja2=3.1.2=pyhd8ed1ab_1
  - json5=0.9.14=pyhd8ed1ab_0
  - jsonpointer=2.4=py39hf3d152e_3
  - jsonschema=4.19.2=pyhd8ed1ab_0
  - jsonschema-specifications=2023.7.1=pyhd8ed1ab_0
  - jsonschema-with-format-nongpl=4.19.2=pyhd8ed1ab_0
  - jupyter-lsp=2.2.0=pyhd8ed1ab_0
  - jupyter_client=8.6.0=pyhd8ed1ab_0
  - jupyter_core=5.5.0=py39hf3d152e_0
  - jupyter_events=0.9.0=pyhd8ed1ab_0
  - jupyter_server=2.10.0=pyhd8ed1ab_0
  - jupyter_server_terminals=0.4.4=pyhd8ed1ab_1
  - jupyterlab=4.0.8=pyhd8ed1ab_0
  - jupyterlab_pygments=0.2.2=pyhd8ed1ab_0
  - jupyterlab_server=2.25.1=pyhd8ed1ab_0
  - ld_impl_linux-64=2.40=h41732ed_0
  - libffi=3.4.2=h7f98852_5
  - libgcc-ng=13.2.0=h807b86a_3
  - libgomp=13.2.0=h807b86a_3
  - libnsl=2.0.1=hd590300_0
  - libsodium=1.0.18=h36c2ea0_1
  - libsqlite=3.44.0=h2797004_0
  - libstdcxx-ng=13.2.0=h7e041cc_3
  - libuuid=2.38.1=h0b41bf4_0
  - libzlib=1.2.13=hd590300_5
  - markupsafe=2.1.3=py39hd1e30aa_1
  - matplotlib-inline=0.1.6=pyhd8ed1ab_0
  - mistune=3.0.2=pyhd8ed1ab_0
  - nbclient=0.8.0=pyhd8ed1ab_0
  - nbconvert-core=7.11.0=pyhd8ed1ab_0
  - nbformat=5.9.2=pyhd8ed1ab_0
  - ncurses=6.4=h59595ed_2
  - nest-asyncio=1.5.8=pyhd8ed1ab_0
  - notebook=7.0.6=pyhd8ed1ab_0
  - notebook-shim=0.2.3=pyhd8ed1ab_0
  - openssl=3.1.4=hd590300_0
  - overrides=7.4.0=pyhd8ed1ab_0
  - packaging=23.2=pyhd8ed1ab_0
  - pandocfilters=1.5.0=pyhd8ed1ab_0
  - parso=0.8.3=pyhd8ed1ab_0
  - pexpect=4.8.0=pyh1a96a4e_2
  - pickleshare=0.7.5=py_1003
  - pip=23.3.1=pyhd8ed1ab_0
  - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1
  - platformdirs=4.0.0=pyhd8ed1ab_0
  - prometheus_client=0.18.0=pyhd8ed1ab_1
  - prompt-toolkit=3.0.41=pyha770c72_0
  - prompt_toolkit=3.0.41=hd8ed1ab_0
  - psutil=5.9.5=py39hd1e30aa_1
  - ptyprocess=0.7.0=pyhd3deb0d_0
  - pure_eval=0.2.2=pyhd8ed1ab_0
  - pycparser=2.21=pyhd8ed1ab_0
  - pygments=2.16.1=pyhd8ed1ab_0
  - pysocks=1.7.1=pyha2e5f31_6
  - python=3.9.18=h0755675_0_cpython
  - python-dateutil=2.8.2=pyhd8ed1ab_0
  - python-fastjsonschema=2.18.1=pyhd8ed1ab_0
  - python-json-logger=2.0.7=pyhd8ed1ab_0
  - python_abi=3.9=4_cp39
  - pytz=2023.3.post1=pyhd8ed1ab_0
  - pyyaml=6.0.1=py39hd1e30aa_1
  - pyzmq=25.1.1=py39h8c080ef_2
  - readline=8.2=h8228510_1
  - referencing=0.30.2=pyhd8ed1ab_0
  - requests=2.31.0=pyhd8ed1ab_0
  - rfc3339-validator=0.1.4=pyhd8ed1ab_0
  - rfc3986-validator=0.1.1=pyh9f0ad1d_0
  - rpds-py=0.12.0=py39h9fdd4d6_0
  - send2trash=1.8.2=pyh41d4057_0
  - setuptools=68.2.2=pyhd8ed1ab_0
  - six=1.16.0=pyh6c4a22f_0
  - sniffio=1.3.0=pyhd8ed1ab_0
  - soupsieve=2.5=pyhd8ed1ab_1
  - stack_data=0.6.2=pyhd8ed1ab_0
  - terminado=0.18.0=pyh0d859eb_0
  - tinycss2=1.2.1=pyhd8ed1ab_0
  - tk=8.6.13=noxft_h4845f30_101
  - tomli=2.0.1=pyhd8ed1ab_0
  - tornado=6.3.3=py39hd1e30aa_1
  - traitlets=5.13.0=pyhd8ed1ab_0
  - types-python-dateutil=2.8.19.14=pyhd8ed1ab_0
  - typing-extensions=4.8.0=hd8ed1ab_0
  - typing_extensions=4.8.0=pyha770c72_0
  - typing_utils=0.1.0=pyhd8ed1ab_0
  - tzdata=2023c=h71feb2d_0
  - uri-template=1.3.0=pyhd8ed1ab_0
  - urllib3=2.1.0=pyhd8ed1ab_0
  - wcwidth=0.2.10=pyhd8ed1ab_0
  - webcolors=1.13=pyhd8ed1ab_0
  - webencodings=0.5.1=pyhd8ed1ab_2
  - websocket-client=1.6.4=pyhd8ed1ab_0
  - wheel=0.41.3=pyhd8ed1ab_0
  - xz=5.2.6=h166bdaf_0
  - yaml=0.2.5=h7f98852_2
  - zeromq=4.3.5=h59595ed_0
  - zipp=3.17.0=pyhd8ed1ab_0
  - pip:
      - salabim==23.3.11.1
prefix: /home/floris/miniforge3/envs/jads_salabim

python 内存 模拟 simpy

评论

0赞 Joe 11/16/2023
我看到您创建了执行的方法,但我没有看到调用这些方法。你在某处调用这些方法吗?如果不是,他们的目的是什么?setupself.mode.monitor(False)
0赞 Joe 11/16/2023
你的意思是让方法实际上是方法吗?setup__init__
1赞 ruudvanderham 11/17/2023
Salabim 在创建时自动调用 Setup 方法。一种用于傻瓜的 init 方法。
0赞 Floris Padt 11/17/2023
我根据 Salabim.org 的提示为每个班级添加了内容。它减少了内存消耗,但不是全部。不幸的是,在运行模拟几个小时后,我所有的 32 GB 再次被消耗殆尽。self.status.monitor(False)
0赞 Joe 11/17/2023
您是否尝试过调用作用域中的名称,看看是否能找到内存占用者?sys.getsizeof

答:

1赞 Floris Padt 11/18/2023 #1

亲爱的萨拉比姆魔术师,

Salabim 的核心开发人员提出了一个补丁,它确实完全解决了这个问题。我通过运行这个非常简单的玩具示例来测试该解决方案,并应用补丁(见下文)超过 10 小时,模拟 4 亿辆汽车正在充电。

内存消耗根本没有增加!!

10 hours of simulation memory still stable

溶液

优雅简约,冲击力巨大

而不是

Car()

Car(name="Car")

评论

0赞 Joe 11/20/2023
这很奇怪。开发人员是否解释了为什么可以阻止内存泄漏?听起来像是源代码中的错误。
0赞 Floris Padt 11/21/2023
嗨,乔,这是回复:可以说,内存泄漏让我重新考虑了名称序列化的方式。并实现了一种新的方法来做到这一点,这可能会影响组件、队列、监视器等的sequence_number。但我怀疑这是否是现有模型中的主要问题。即将推出的版本将采用这种新方式。敬请关注。顺便说一句,您能否指出答案是否有用,以便其他人也会在补丁之前找到它?
0赞 Floris Padt 12/2/2023 #2

2023 年 11 月 28 日,Salabim 软件包的新版本 (23.3.12) 已发布,它解决了此问题,并且不再需要建议的补丁。