[英]improving speed of Python module import
之前已经问过如何加速 Python 模块的导入的问题( 加速 python “导入”加载器和Python -- 加速导入? ),但没有具体示例,也没有产生公认的解决方案。 因此,我将在这里再次讨论这个问题,但这次是一个具体的例子。
我有一个 Python 脚本,它从磁盘加载 3-D 图像堆栈,对其进行平滑处理,然后将其显示为电影。 当我想快速查看我的数据时,我从系统命令提示符调用这个脚本。 我对平滑数据所需的 700 毫秒没问题,因为这与 MATLAB 相当。 但是,导入模块需要额外的 650 毫秒。 所以从用户的角度来看,Python 代码的运行速度只有一半。
这是我要导入的一系列模块:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import scipy.ndimage
import scipy.signal
import sys
import os
当然,并非所有模块的导入速度都一样慢。 罪魁祸首是:
matplotlib.pyplot [300ms]
numpy [110ms]
scipy.signal [200ms]
我已经尝试过使用from
,但这并没有更快。 由于 Matplotlib 是罪魁祸首,并且因屏幕更新缓慢而闻名,因此我寻找了替代方案。 一个是 PyQtGraph,但导入需要 550 毫秒。
我知道一个明显的解决方案,即从交互式 Python 会话而不是系统命令提示符调用我的函数。 这很好,但它太像 MATLAB,我更喜欢从系统提示中获得我的函数的优雅。
我是 Python 的新手,现在我不确定如何进行。 由于我是新手,我很感激有关如何实施建议解决方案的链接。 理想情况下,我正在寻找一个简单的解决方案(我们不是所有人吗!)因为代码需要在多台 Mac 和 Linux 机器之间移植。
不是问题的实际答案,而是关于如何使用 Python 3.7 和金枪鱼(我的一个小项目)分析导入速度的提示:
python3 -X importtime -c "import scipy" 2> scipy.log
tuna scipy.log
您可以构建一个简单的服务器/客户端,服务器运行不断地制作和更新绘图,而客户端只是通信下一个要处理的文件。
我根据socket
模块文档中的基本示例编写了一个简单的服务器/客户端示例: http : //docs.python.org/2/library/socket.html#example
这是 server.py:
# expensive imports
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import scipy.ndimage
import scipy.signal
import sys
import os
# Echo server program
import socket
HOST = '' # Symbolic name meaning all available interfaces
PORT = 50007 # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
while 1:
conn, addr = s.accept()
print 'Connected by', addr
data = conn.recv(1024)
if not data: break
conn.sendall("PLOTTING:" + data)
# update plot
conn.close()
和客户端.py:
# Echo client program
import socket
import sys
HOST = '' # The remote host
PORT = 50007 # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.sendall(sys.argv[1])
data = s.recv(1024)
s.close()
print 'Received', repr(data)
你只需运行服务器:
python server.py
进行导入,然后客户端只需通过套接字发送新文件的文件名即可绘制:
python client.py mytextfile.txt
然后服务器更新绘图。
在我的机器上运行导入需要 0.6 秒,而运行client.py
0.03 秒。
您可以使用imp
手动导入模块。 请参阅此处的文档。
例如, import numpy as np
可能可以写成
import imp
np = imp.load_module("numpy",None,"/usr/lib/python2.7/dist-packages/numpy",('','',5))
这将使 python sys.path
浏览整个sys.path
来查找所需的包。
也可以看看:
1.35 秒并不长,但我想如果您习惯于将其减半进行“快速检查”,那么也许看起来如此。
Andrea 建议了一个简单的客户端/服务器设置,但在我看来,您可以轻松调用对脚本的非常轻微的修改,并在工作时保持控制台窗口打开:
我假设您的脚本每次都是相同的,即您不需要每次都给它图像堆栈位置或任何特定命令(但这些也很容易做到!)。
示例 RAAC's_Script.py:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import scipy.ndimage
import scipy.signal
import sys
import os
print('********* RAAC\'s Script Now Running *********')
while True: # Loops forever
# Display a message and wait for user to enter text followed by enter key.
# In this case, we're not expecting any text at all and if there is any it's ignored
input('Press Enter to test image stack...')
'''
*
*
**RAAC's Code Goes Here** (Make sure it's indented/inside the while loop!)
*
*
'''
要结束脚本,请关闭控制台窗口或按 ctrl+c。
我已经使这尽可能简单,但是它只需要很少的额外处理就可以很好地退出,根据输入做一些稍微不同的事情等。
您可以使用延迟导入,但这取决于您的用例。
如果它是一个应用程序,您可以运行 GUI 所需的模块,然后在加载窗口后,您可以导入所有模块。
如果它是一个模块并且用户不使用所有依赖项,则可以在函数内部导入。
[警告]我认为这是针对 pep8 并且在某些地方不推荐的,但这背后的所有原因主要是可读性(尽管我可能是错的......)和一些构建器(例如 pyinstaller)捆绑(可以通过添加来解决)缺少对规范的依赖项参数)
如果您使用延迟导入,请使用注释以便用户知道存在额外的依赖项。
例子:
import numpy as np
# Lazy imports
# import matplotlib.pyplot as plt
def plot():
import matplotlib.pyplot as plt
# Your function here
# This will be imported during runtime
对于某些特定的图书馆,我认为这是必要的。
您还可以在__init__.py
创建一些我们称之为 api 的
例如关于 scikit 学习。 如果您导入 sklearn 然后调用某个模型,则找不到它并引发错误。 您需要更具体,然后直接导入子模块。 虽然这对用户来说可能不方便,但恕我直言,这是一种很好的做法,可以显着减少导入时间。
通常 10% 的导入库花费 90% 的导入时间。 非常简单的分析工具是 line_profiler
import line_profiler
import atexit
profile = line_profiler.LineProfiler()
atexit.register(profile.print_stats)
@profile
def profiled_function():
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
profiled_function()
这给出了结果
Line # Hits Time Per Hit % Time Line Contents
==============================================================
20 @profile
21 def profiled_function():
22
23 1 2351852.0 2351852.0 6.5 import numpy as np
24 1 6545679.0 6545679.0 18.0 import pandas as pd
25 1 27485437.0 27485437.0 75.5 import matplotlib.pyplot as plt
三个库的 75% 的导入时间是 matplotlib(这并不意味着它写得不好,它只是需要大量的东西用于图形输出)
笔记:
如果您在一个模块中导入库,则其他导入无需任何费用,它是全局共享的...
另一个注意事项:
如果直接使用从Python导入(如pathlib
, subprocess
等)不使用延迟加载,Python模块导入时间接近于零,也不需要从我的经验,优化...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.