我正在使用 inkscape 将一堆 SVG 图像转换为 PNG。 单线程:
import subprocess
import time
import os
inkscape_path = r'C:\Program Files\Inkscape\bin\inkscape.com'
steps=30
filenames = []
processes = []
# t_start = time.process_time()
t_start = time.time()
for i in range(steps):
template = bytes(f"""<?xml version="1.0" encoding="UTF-8"?>
<svg width="100" height="100" viewBox="-10 -10 30 30" xmlns="http://www.w3.org/2000/svg">
<line x1="0" y1="0" x2="{i*9/(steps-1)+1}" y2="0" stroke="green"/>
</svg>
""",'UTF-8')
filename = f'img{i:02}.png'
filenames.append(filename)
process = subprocess.run([inkscape_path, '-p', '-o', filename],input=template )
# elapsed_time = time.process_time() - t_start
elapsed_time = time.time() - t_start
print(elapsed_time)
这可以工作,30 个图像总共需要 85 秒。
如果我用 communications() 尝试它,它会等待每个进程的完成。因此,我将超时设置为 0 并忽略引发的异常。
import subprocess
import time
import os
inkscape_path = r'C:\Program Files\Inkscape\bin\inkscape.com'
steps=30
filenames = []
processes = []
# t_start = time.process_time()
t_start = time.time()
for i in range(steps):
template = bytes(f"""<?xml version="1.0" encoding="UTF-8"?>
<svg width="100" height="100" viewBox="-10 -10 30 30" xmlns="http://www.w3.org/2000/svg">
<line x1="0" y1="0" x2="{i*9/(steps-1)+1}" y2="0" stroke="green"/>
</svg>
""",'UTF-8')
filename = f'img{i:02}.png'
filenames.append(filename)
process = subprocess.Popen([inkscape_path, '-p', '-o', filename],stdin= subprocess.PIPE, env=dict(os.environ, SELF_CALL="xxx") )
try:
process.communicate(template,timeout=0)
except:
pass
processes.append(process)
for p in processes:
p.wait()
# elapsed_time = time.process_time() - t_start
elapsed_time = time.time() - t_start
print(elapsed_time)
这有效并需要 30 秒,但我认为这不是一个干净的方法。
如何并行运行多个这些子进程以干净的方式。最好在 1 行中。
(SELF_CALL 是一种解决方法,因为 inkscape 有时会在多个实例运行时引发异常)
可以使用线程池来并行运行多个子进程,而无需等待每个子进程完成。以下是如何使用
concurrent.futures
库执行此操作的示例:
import subprocess
import time
import os
from concurrent.futures import ThreadPoolExecutor
inkscape_path = r'C:\Program Files\Inkscape\bin\inkscape.com'
steps = 30
def generate_svg(i):
return bytes(f"""<?xml version="1.0" encoding="UTF-8"?>
<svg width="100" height="100" viewBox="-10 -10 30 30" xmlns="http://www.w3.org/2000/svg">
<line x1="0" y1="0" x2="{i*9/(steps-1)+1}" y2="0" stroke="green"/>
</svg>
""", 'UTF-8')
def convert_to_png(i):
filename = f'img{i:02}.png'
template = generate_svg(i)
process = subprocess.run(
[inkscape_path, '-p', '-o', filename],
input=template,
env=dict(os.environ, SELF_CALL="xxx")
)
t_start = time.time()
# 使用线程池并行运行转换
with ThreadPoolExecutor() as executor:
executor.map(convert_to_png, range(steps))
elapsed_time = time.time() - t_start
print(elapsed_time)
这个代码示例做了以下事情:
-
定义
generate_svg
函数: 此函数接受一个索引i
并返回相应的 SVG 图像数据作为字节字符串。 -
定义
convert_to_png
函数: 此函数接受一个索引i
,生成 SVG 数据,然后使用subprocess.run
调用 Inkscape 将其转换为 PNG。 -
使用
ThreadPoolExecutor
: 创建一个线程池,并使用executor.map
函数将convert_to_png
函数并行应用于range(steps)
中的每个索引。这将启动多个线程,每个线程负责将一个 SVG 图像转换为 PNG。 - 测量执行时间: 记录开始和结束时间,并打印总执行时间。
通过使用线程池,可以利用多核处理器来并行处理图像转换,从而显着减少总执行时间。
标签:python,subprocess From: 78808552