这个问题多次被问过SO(例如here),但还没有真正的答案。
我正在编写一个用于呈现模板的简短命令行工具。它是使用Makefile:
进行的i = $(wildcard *.in)
o = $(patsubst %.in, %.out, $(t))
all: $(o)
%.out: %.in
./script.py -o $@ $<
在这个虚拟示例中,Makefile会解析每个.in
文件以生成.out
文件。使用make
非常方便,因为我在此脚本之前和之后有很多其他操作要触发。此外,我希望尽可能保持KISS。
因此,我希望保持我的工具简单,愚蠢,并使用语法
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.2s(处理时间约为60ms,导入指令约为1140ms):
$ 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来解决我最大的问题:由于导入时间不长,它还不适合简单的命令行工具。
答案 0 :(得分:3)
这并不容易,但您可以将程序转换为后台程序并处理命令来处理文件。
另一个程序可以将处理命令提供给它,从而使真正的开始变得非常容易。
答案 1 :(得分:1)
将模板部件写为单独的过程。第一次运行“script.py”时,它将启动这个单独的进程。一旦进程存在,它就可以通过命名管道传递输入/输出文件名。如果进程没有输入x秒,它会自动退出。 x的大小取决于您的需求
因此,参数通过script.py写入命名管道传递给长时间运行的进程。导入只发生一次(假设输入相当频繁),而BPL指出这会使一切运行得更快
答案 2 :(得分:0)
您可以使用glob
对所需文件执行该操作。
import glob
in_files=glob.glob('*.in')
out_files=glob.glob('*.out')
因此,您处理同一脚本中的所有文件,而不是每次都使用每对文件调用脚本。至少你不必每次都开始python。
答案 3 :(得分:0)
问题显而易见,现在你得到了:
cost(file) = 1.2s = 60ms + 1040ms
,表示:
cost(N*files) = N*1.2s
现在,你为什么不把它变成:
cost1(files) = 1040ms + N*60ms
这样,理论上处理100个文件将是7,04s而不是120s
修改强>
因为我收到了这个问题的投票,我会发一个小例子,让我们假设你有这个python文件:
# foo.py
import numpy
import cv2
print sys.argv[0]
我的盒子上的执行时间是1.3秒,现在,如果我这样做:
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次