如何提高 python 导入速度?
How to improve python import speed?
这个问题已经在SO上被问过很多次了(例如here),但是还没有真正的答案。
我正在编写一个简短的命令行工具来呈现模板。它是使用 Makefile 构建的:
i = $(wildcard *.in)
o = $(patsubst %.in, %.out, $(t))
all: $(o)
%.out: %.in
./script.py -o $@ $<
在这个虚拟示例中,Makefile 解析每个 .in
文件以生成一个 .out
文件。使用make
对我来说非常方便,因为我在这个脚本之前和之后还有很多其他的动作要触发。此外,我想尽可能保持KISS。
Thus, I want to keep my tool simple, stupid and process each file separately using the syntax script -o out in
我的脚本使用以下内容:
#!/usr/bin/env python
from jinja2 import Template, nodes
from jinja2.ext import Extension
import hiyapyco
import argparse
import re
...
问题是每次执行花费我大约 1.2 秒(处理约 60 毫秒,导入指令约 1140 毫秒):
$ time ./script.py -o foo.out foo.in
real 0m1.625s
user 0m0.452s
sys 0m1.185s
我的 Makefile 对 100 个文件的整体执行是荒谬的:~100 个文件 x 1.2s = 120s。
这不是解决方案,但这应该是解决方案。
我可以使用什么替代方案?
编辑
我喜欢 Python,因为它的语法可读性强,而且它的社区规模很大。在这种特殊情况下(命令行工具),我不得不承认 Perl 仍然是一个不错的选择。用 Perl(也是一种解释语言)编写的相同脚本大约快 12 倍(使用 Text::Xslate
)。
无论如何我都不想推广 Perl 我只是想解决我最大的问题 Python:由于导入时间短,它还不是一种适合简单命令行工具的语言。
您可以使用 glob
对您需要的文件执行该操作。
import glob
in_files=glob.glob('*.in')
out_files=glob.glob('*.out')
因此,您在同一个脚本中处理所有文件,而不是每次对每对文件都调用脚本。至少这样你不必每次都开始python。
好像很清楚问题出在哪里,现在你得到:
cost(file) = 1.2s = 60ms + 1040ms
,意思是:
cost(N*files) = N*1.2s
现在,你为什么不把它改成:
cost1(files) = 1040ms + N*60ms
这样,理论上处理 100 个文件将是 7,04s 而不是 120s
编辑:
因为我收到了对这个问题的反对票,所以我将 post 举个小例子,假设你有这个 python 文件:
# foo.py
import numpy
import cv2
print sys.argv[0]
我的盒子上的执行时间是1.3s,现在,如果我这样做:
for /l %x in (1, 1, 100) do python foo.py
我会得到100*1.3s的执行时间,我的建议是把foo.py变成这样:
import numpy
import cv2
def whatever_rendering_you_want_to_do(file):
pass
for file in sys.argv:
whatever_rendering_you_want_to_do(file)
这样你只导入一次而不是 100 次
这并不容易,但您可以将您的程序变成一个位于后台并处理命令以处理文件的程序。
另一个程序可以将处理命令提供给它,从而使真正的开始变得非常容易。
将模板部分编写为一个单独的过程。第一次 "script.py" 是 运行 它将启动这个单独的进程。一旦进程存在,它就可以通过命名管道传递 input/output 文件名。如果进程在 x 秒内没有输入,它会自动退出。 x有多大取决于你的需求
因此,参数通过 script.py 写入命名管道传递给长 运行ning 进程。导入只发生一次(前提是输入相当频繁),正如 BPL 指出的那样,这将使一切 运行 更快
这个问题已经在SO上被问过很多次了(例如here),但是还没有真正的答案。
我正在编写一个简短的命令行工具来呈现模板。它是使用 Makefile 构建的:
i = $(wildcard *.in)
o = $(patsubst %.in, %.out, $(t))
all: $(o)
%.out: %.in
./script.py -o $@ $<
在这个虚拟示例中,Makefile 解析每个 .in
文件以生成一个 .out
文件。使用make
对我来说非常方便,因为我在这个脚本之前和之后还有很多其他的动作要触发。此外,我想尽可能保持KISS。
Thus, I want to keep my tool simple, stupid and process each file separately using the syntax
script -o out in
我的脚本使用以下内容:
#!/usr/bin/env python
from jinja2 import Template, nodes
from jinja2.ext import Extension
import hiyapyco
import argparse
import re
...
问题是每次执行花费我大约 1.2 秒(处理约 60 毫秒,导入指令约 1140 毫秒):
$ time ./script.py -o foo.out foo.in
real 0m1.625s
user 0m0.452s
sys 0m1.185s
我的 Makefile 对 100 个文件的整体执行是荒谬的:~100 个文件 x 1.2s = 120s。
这不是解决方案,但这应该是解决方案。
我可以使用什么替代方案?
编辑
我喜欢 Python,因为它的语法可读性强,而且它的社区规模很大。在这种特殊情况下(命令行工具),我不得不承认 Perl 仍然是一个不错的选择。用 Perl(也是一种解释语言)编写的相同脚本大约快 12 倍(使用 Text::Xslate
)。
无论如何我都不想推广 Perl 我只是想解决我最大的问题 Python:由于导入时间短,它还不是一种适合简单命令行工具的语言。
您可以使用 glob
对您需要的文件执行该操作。
import glob
in_files=glob.glob('*.in')
out_files=glob.glob('*.out')
因此,您在同一个脚本中处理所有文件,而不是每次对每对文件都调用脚本。至少这样你不必每次都开始python。
好像很清楚问题出在哪里,现在你得到:
cost(file) = 1.2s = 60ms + 1040ms
,意思是:
cost(N*files) = N*1.2s
现在,你为什么不把它改成:
cost1(files) = 1040ms + N*60ms
这样,理论上处理 100 个文件将是 7,04s 而不是 120s
编辑:
因为我收到了对这个问题的反对票,所以我将 post 举个小例子,假设你有这个 python 文件:
# foo.py
import numpy
import cv2
print sys.argv[0]
我的盒子上的执行时间是1.3s,现在,如果我这样做:
for /l %x in (1, 1, 100) do python foo.py
我会得到100*1.3s的执行时间,我的建议是把foo.py变成这样:
import numpy
import cv2
def whatever_rendering_you_want_to_do(file):
pass
for file in sys.argv:
whatever_rendering_you_want_to_do(file)
这样你只导入一次而不是 100 次
这并不容易,但您可以将您的程序变成一个位于后台并处理命令以处理文件的程序。
另一个程序可以将处理命令提供给它,从而使真正的开始变得非常容易。
将模板部分编写为一个单独的过程。第一次 "script.py" 是 运行 它将启动这个单独的进程。一旦进程存在,它就可以通过命名管道传递 input/output 文件名。如果进程在 x 秒内没有输入,它会自动退出。 x有多大取决于你的需求
因此,参数通过 script.py 写入命名管道传递给长 运行ning 进程。导入只发生一次(前提是输入相当频繁),正如 BPL 指出的那样,这将使一切 运行 更快