Arc*_*s B 15 python performance subprocess python-performance
考虑以下循环:
for i in range(20):
if i == 10:
subprocess.Popen(["echo"]) # command 1
t_start = time.time()
1+1 # command 2
t_stop = time.time()
print(t_stop - t_start)
Run Code Online (Sandbox Code Playgroud)
当"命令1"在其之前运行时,"命令2"命令系统地运行更长时间.下图显示了1+1作为循环索引函数的执行时间i,平均超过100次运行.
执行1+1时比之前慢30倍subprocess.Popen.
Run Code Online (Sandbox Code Playgroud)
以下是此循环的执行时间图,平均超过100次运行:
time.sleep()或使用rawkit的libraw C++绑定初始化(libraw.bindings.LibRaw())时,我们获得相同的效果.但是,使用其他带有C++绑定的库(如libraw.py或OpenCV)cv2.warpAffine()不会影响执行时间.打开文件也不是.
time.time()由于它是可见的timeit.timeit(),甚至是在print()结果出现时手动测量.subprocess.Popen)和"命令2" 之间执行许多不同的(可能是CPU和内存消耗)操作时,也会发生这种情况.arr += 1操作可能需要300 ms!问题:什么可能导致这种影响,为什么它只影响当前的循环迭代?
我怀疑它可能与上下文切换有关,但这似乎并不能解释为什么整个循环迭代会受到影响.如果上下文切换确实是原因,为什么有些命令会触发它而其他命令却没有?
我的猜测是,这是由于Python代码从CPU /内存系统中的各种缓存中逐出
该perflib程序包可用于提取有关缓存状态的更详细的CPU级别统计信息 - 即命中/未命中数.
电话LIBPERF_COUNT_HW_CACHE_MISSES结束后,我得到了5倍的柜台 Popen():
from subprocess import Popen, DEVNULL
from perflib import PerfCounter
import numpy as np
arr = []
p = PerfCounter('LIBPERF_COUNT_HW_CACHE_MISSES')
for i in range(100):
ti = []
p.reset()
p.start()
ti.extend(p.getval() for _ in range(7))
Popen(['echo'], stdout=DEVNULL)
ti.extend(p.getval() for _ in range(7))
p.stop()
arr.append(ti)
np.diff(np.array(arr), axis=1).mean(axis=0).astype(int).tolist()
Run Code Online (Sandbox Code Playgroud)
给我:
2605, 2185, 2127, 2099, 2407, 2120,
5481210,
16499, 10694, 10398, 10301, 10206, 10166
Run Code Online (Sandbox Code Playgroud)
(在非标准位置打破的行以指示代码流)