为什么Python操作在调用后慢了30倍时间。睡觉或者子流程。Popen?

2024-05-16 12:18:56 发布

您现在位置:Python中文网/ 问答频道 /正文

考虑以下循环:

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)

“命令2”在“命令1”之前运行时,系统地运行“命令2”需要更长的时间。下面的图显示了1+1的执行时间,它是循环索引i的函数,平均运行100次。在

前面加subprocess.Popen时,1+1的执行速度慢30倍。

Execution time of <code>1+1</code> as a function of loop index


更奇怪的是。人们可能认为只有subprocess.Popen()之后运行的第一个命令受到影响,但事实并非如此。下面的循环显示当前循环迭代中的所有命令都会受到影响。但随后的循环迭代似乎基本上是正常的。在

^{pr2}$

下面是此循环的执行时间图,平均运行100次以上:

Execution times of <code>1+1, print(1), and var += 1</code> as a function of loop index


更多备注:

  • 在替换^ {< CD5> }(“命令1”)时,与{{CD7}}或rawkit’s libraw C++绑定初始化(^ {CD8}})相同。但是,使用C++绑定的其他库,如libraw.py,或OpenCV的^ {CD9}}不影响执行时间。也不要打开文件。在
  • 这种影响不是由time.time()引起的,因为它在timeit.timeit()中是可见的,甚至在{}结果出现时也可以手动测量。在
  • 它在没有for循环的情况下也会发生。在
  • 即使在“command1”(subprocess.Popen)和“command2”之间执行了许多不同的(可能占用CPU和内存)操作,也会发生这种情况。在
  • 对于Numpy数组,速度减慢似乎与数组的大小成正比。对于相对较大的数组(~60 M点),一个简单的arr += 1操作可能需要300毫秒!在

问题:什么可能导致这种效果,为什么它只影响当前循环迭代?在

我怀疑这可能与上下文切换有关,但这似乎不能解释为什么整个循环迭代会受到影响。如果上下文切换确实是原因,为什么有些命令会触发它,而另一些则不会呢?在


Tags: in命令fortime时间情况range数组
1条回答
网友
1楼 · 发布于 2024-05-16 12:18:56

我的猜测是,这是由于Python代码被从CPU/内存系统中的各种缓存中逐出所致

perflib包可用于提取有关缓存状态(即命中/未命中数)的更详细的CPU级统计信息。在

Popen()调用之后,我得到LIBPERF_COUNT_HW_CACHE_MISSES计数器的~5倍:

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()                                                

给我:

^{pr2}$

(在非标准位置断行表示代码流)

相关问题 更多 >