在python 3.7.2中导入numpy后的RAM使用情况

时间:2019-02-13 17:18:15

标签: python numpy conda ram

我使用python 3.7.2 win32运行conda 4.6.3。在python中,当我导入numpy时,我看到RAM使用量增加了80MB。由于我正在使用多处理程序,因此我想知道这是否正常,是否还有其他方法可以避免此RAM开销?请在下面查看相关软件包(从conda列表中)的所有版本:

  

python ........... 3.7.2 h8c8aaf0_2

     

mkl_fft ........... 1.0.10 py37h14836fe_0

     

mkl_random..1.0.2 py37h343c172_0

     

numpy ........... 1.15.4 py37h19fb1c0_0

     

numpy-base..1.15.4 py37hc3f5095_0

谢谢!

2 个答案:

答案 0 :(得分:0)

您无法避免这笔费用,但它可能并不像看起来那样糟糕。 numpy库(仅包含C的副本libopenblasp,加上所有Python numpy扩展模块)在磁盘上占据60 MB以上的空间,它们都将通过内存映射到您的Python导入过程添加所有Python模块以及动态加载的内存,这些内存都涉及加载和初始化所有模块,并且报告的RAM使用量增加80 MB相当正常。

说:

  1. C库和Python扩展模块被映射到内存中,但这并不意味着它们占据了“真正的” RAM;如果不使用给定页面中的代码路径,则该页面将永远不会被加载,或者将在内存压力下被丢弃(甚至不会写入页面文件,因为它总是可以从原始DLL重新加载它)。 / li>
  2. 在类似UNIX的系统上,当您forkmultiprocessing默认在Windows以外的任何地方都执行此操作)时,内存将在写时复制模式下在父进程和工作进程之间共享。由于通常不会编写代码本身,因此唯一的代价就是页表本身(它们引用的内存的一小部分),并且父级和子级都将共享该RAM。

遗憾的是,在Windows上,fork是不可行的(除非您在Windows上运行Ubuntu bash,在这种情况下,它仅是勉强可用的Windows,实际上是Linux),因此您很可能在每个过程中支付更多的内存成本。但是即使在libopenblasp(支持numpy的大部分内容的C库)中,每个进程也将被重新映射,但是操作系统应在各个进程之间适当地共享只读内存(如果不是全部,则很大一部分) ,以及Python扩展模块)。

基本上,直到这确实导致问题(而且不太可能造成问题)之前,请不必担心。

答案 1 :(得分:0)

[NumPy]: NumPy

  

是使用Python进行科学计算的基本软件包。

这是一个 big 软件包,旨在与大型数据集一起使用,并且(主要)针对速度进行了优化。
如果您查看它的 __ init __。py (在导入时会执行(例如:import numpy)),您会注意到它导入了很多项目(包/模块):

  • 这些物品本身,可能会导入其他物品
  • 其中一些是扩展模块 .pyd s( .dll s)或 .so s )加载到当前进程中(以及它们的依赖项)

我已经准备好演示了。

code.py

#!/usr/bin/env python3

import sys
import os
import psutil
#import pprint


def main():
    display_text = "This {:s} screenshot was taken. Press <Enter> to continue ... "
    pid = os.getpid()
    print("Pid: {:d}\n".format(pid))
    p = psutil.Process(pid=pid)
    mod_names0 = set(k for k in sys.modules)
    mi0 = p.memory_info()

    input(display_text.format("first"))

    import numpy

    input(display_text.format("second"))

    mi1 = p.memory_info()
    for idx, mi in enumerate([mi0, mi1], start=1):
        print("\nMemory info ({:d}): {:}".format(idx, mi))

    print("\nExtra modules imported by `{:s}` :".format(numpy.__name__))
    print(sorted(set(k for k in sys.modules) - mod_names0))
    #pprint.pprint({k: v for k, v in sys.modules.items() if k not in mod_names0})
    print("\nDone.")


if __name__ == "__main__":
    print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
    main()

输出

[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q054675983]> "e:\Work\Dev\VEnvs\py_064_03.06.08_test0\Scripts\python.exe" code.py
Python 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018, 00:16:47) [MSC v.1916 64 bit (AMD64)] on win32

Pid: 27160

This first screenshot was taken. Press <Enter> to continue ...
This second screenshot was taken. Press <Enter> to continue ...

Memory info (1): pmem(rss=15491072, vms=8458240, num_page_faults=4149, peak_wset=15495168, wset=15491072, peak_paged_pool=181160, paged_pool=180984, peak_nonpaged_pool=13720, nonpaged_pool=13576, pagefile=8458240, peak_pagefile=8458240, private=8458240)

Memory info (2): pmem(rss=27156480, vms=253882368, num_page_faults=7283, peak_wset=27205632, wset=27156480, peak_paged_pool=272160, paged_pool=272160, peak_nonpaged_pool=21640, nonpaged_pool=21056, pagefile=253882368, peak_pagefile=253972480, private=253882368)

Extra modules imported by `numpy` :
['_ast', '_bisect', '_blake2', '_compat_pickle', '_ctypes', '_decimal', '_hashlib', '_pickle', '_random', '_sha3', '_string', '_struct', 'argparse', 'ast', 'atexit', 'bisect', 'copy', 'ctypes', 'ctypes._endian', 'cython_runtime', 'decimal', 'difflib', 'gc', 'gettext', 'hashlib', 'logging', 'mtrand', 'numbers', 'numpy', 'numpy.__config__', 'numpy._distributor_init', 'numpy._globals', 'numpy._import_tools', 'numpy.add_newdocs', 'numpy.compat', 'numpy.compat._inspect', 'numpy.compat.py3k', 'numpy.core', 'numpy.core._internal', 'numpy.core._methods', 'numpy.core._multiarray_tests', 'numpy.core.arrayprint', 'numpy.core.defchararray', 'numpy.core.einsumfunc', 'numpy.core.fromnumeric', 'numpy.core.function_base', 'numpy.core.getlimits', 'numpy.core.info', 'numpy.core.machar', 'numpy.core.memmap', 'numpy.core.multiarray', 'numpy.core.numeric', 'numpy.core.numerictypes', 'numpy.core.records', 'numpy.core.shape_base', 'numpy.core.umath', 'numpy.ctypeslib', 'numpy.fft', 'numpy.fft.fftpack', 'numpy.fft.fftpack_lite', 'numpy.fft.helper', 'numpy.fft.info', 'numpy.lib', 'numpy.lib._datasource', 'numpy.lib._iotools', 'numpy.lib._version', 'numpy.lib.arraypad', 'numpy.lib.arraysetops', 'numpy.lib.arrayterator', 'numpy.lib.financial', 'numpy.lib.format', 'numpy.lib.function_base', 'numpy.lib.histograms', 'numpy.lib.index_tricks', 'numpy.lib.info', 'numpy.lib.mixins', 'numpy.lib.nanfunctions', 'numpy.lib.npyio', 'numpy.lib.polynomial', 'numpy.lib.scimath', 'numpy.lib.shape_base', 'numpy.lib.stride_tricks', 'numpy.lib.twodim_base', 'numpy.lib.type_check', 'numpy.lib.ufunclike', 'numpy.lib.utils', 'numpy.linalg', 'numpy.linalg._umath_linalg', 'numpy.linalg.info', 'numpy.linalg.lapack_lite', 'numpy.linalg.linalg', 'numpy.ma', 'numpy.ma.core', 'numpy.ma.extras', 'numpy.matrixlib', 'numpy.matrixlib.defmatrix', 'numpy.polynomial', 'numpy.polynomial._polybase', 'numpy.polynomial.chebyshev', 'numpy.polynomial.hermite', 'numpy.polynomial.hermite_e', 'numpy.polynomial.laguerre', 'numpy.polynomial.legendre', 'numpy.polynomial.polynomial', 'numpy.polynomial.polyutils', 'numpy.random', 'numpy.random.info', 'numpy.random.mtrand', 'numpy.testing', 'numpy.testing._private', 'numpy.testing._private.decorators', 'numpy.testing._private.nosetester', 'numpy.testing._private.pytesttester', 'numpy.testing._private.utils', 'numpy.version', 'pathlib', 'pickle', 'pprint', 'random', 'string', 'struct', 'tempfile', 'textwrap', 'unittest', 'unittest.case', 'unittest.loader', 'unittest.main', 'unittest.result', 'unittest.runner', 'unittest.signals', 'unittest.suite', 'unittest.util', 'urllib', 'urllib.parse']

Done.

以及(之前之后导入)屏幕截图([MS.Docs]: Process Explorer):

Img0 - before

Img1 - after

作为个人评论,我认为〜80 MiB (或确切的数量)对于当前的“时代”来说是不俗的,其特征是硬件数量高得离谱资源,尤其是在记忆领域。
此外,与数组本身所需的数量相比,这可能并不重要。如果不是这种情况,您可能应该考虑远离 numpy

有一种方法可以减少内存占用,方法是选择性地仅导入包含所需功能的模块(我个人的建议是反对),然后绕过 __ init __。py