Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python itertools与用于展平和重复的生成器表达式-我们如何解释这些计时结果?_Python_Performance_Itertools_Generator Expression - Fatal编程技术网

Python itertools与用于展平和重复的生成器表达式-我们如何解释这些计时结果?

Python itertools与用于展平和重复的生成器表达式-我们如何解释这些计时结果?,python,performance,itertools,generator-expression,Python,Performance,Itertools,Generator Expression,出于对的讨论,我决定尝试一些性能测试。我设置的任务稍微简单一些-给定一个源列表a,我们希望创建一个lazy iterable,它将a的每个元素重复N次: def测试(实施): A、 N=列表('abc'),3 断言列表(实现(A,N))==list('aaabbccc') 我提出了几个实现,并对它们进行了测试: 从itertools导入链,重复,星图 从timeit导入timeit 展平=链从可调 def消耗(iterable): 对于iterable中的uu: 通过 #快速接近 def工具(

出于对的讨论,我决定尝试一些性能测试。我设置的任务稍微简单一些-给定一个源列表
a
,我们希望创建一个lazy iterable,它将a的每个元素重复N次:

def测试(实施): A、 N=列表('abc'),3 断言列表(实现(A,N))==list('aaabbccc') 我提出了几个实现,并对它们进行了测试:

从itertools导入链,重复,星图
从timeit导入timeit
展平=链从可调
def消耗(iterable):
对于iterable中的uu:
通过
#快速接近
def工具(原始,计数):
返回展平(贴图(重复、原始、重复(计数)))
def tools_star(原始,计数):
返回展平(星图(重复,压缩(原始,重复(计数)))
def混合(原始,计数):
返回展平(对原件中的a重复(a,计数)
#慢进
def混合2(原始,计数):
返回值(x代表a原件,x代表重复(a,计数))
def显式(原始,计数):
对于原件:
对于范围内的(计数):
产生
def发生器(原始,计数):
返回值(a为原始值,a为范围内(计数))
def混合3(原始,计数):
原稿中a的返回展平((a表示范围内(计数))值)
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
对于impl in(工具、工具、星型、混合、混合2、显式、生成器、混合3):
对于中的消费(消费,列表):
to_时间=λ:消耗量(impl(列表(范围(1000)),1000))
已用时间=时间(到时间,数字=100)
打印(f'{consumption.\uuuuuu name\uuuuuu}({impl.\uuuuuuu name\uuuuuuuuu}):{已用时间:.2f})
以下是我的机器上计时结果的三个示例:

consume(tools): 1.10
list(tools): 2.96
consume(tools_star): 1.10
list(tools_star): 2.97
consume(mixed): 1.11
list(mixed): 2.91
consume(mixed2): 4.60
list(mixed2): 6.53
consume(explicit): 5.45
list(explicit): 8.09
consume(generator): 5.98
list(generator): 7.62
consume(mixed3): 5.75
list(mixed3): 7.67

consume(tools): 1.10
list(tools): 2.88
consume(tools_star): 1.10
list(tools_star): 2.89
consume(mixed): 1.11
list(mixed): 2.87
consume(mixed2): 4.56
list(mixed2): 6.39
consume(explicit): 5.42
list(explicit): 7.24
consume(generator): 5.91
list(generator): 7.48
consume(mixed3): 5.80
list(mixed3): 7.61

consume(tools): 1.14
list(tools): 2.98
consume(tools_star): 1.10
list(tools_star): 2.90
consume(mixed): 1.11
list(mixed): 2.92
consume(mixed2): 4.76
list(mixed2): 6.49
consume(explicit): 5.69
list(explicit): 7.38
consume(generator): 5.68
list(generator): 7.52
consume(mixed3): 5.75
list(mixed3): 7.86
由此我得出以下结论:

  • itertools
    工具提供了巨大的性能提升,但前提是我们同时使用它们来“展平”迭代器(
    itertools.chain.from_iterable
    而不是通过嵌套的
    for
    表达式展平),并生成子序列(
    itertools.repeat
    而不是
    range
    )。只使用<代码>重复只提供了一个小的改进,并且只使用<代码>链。从_iterable实际上似乎让事情变得更糟

  • 对于完整的
    itertools
    实现,我们如何迭代输入序列似乎并不重要——无论是使用生成器表达式、使用
    map
    还是使用
    itertools.starmap
    。(这并不奇怪,因为这里只发生了O(len(A))操作,而不是O(len(A)*N)。星图的
    starmap
    方法非常笨拙,肯定不是我推荐的方法,但我将其包括在内,因为原始激励讨论中的代码使用了它。)

  • 从iterable创建列表所增加的开销量在不同方法和不同计时运行(请注意两次运行的
    list(explicit)
    结果的差异)-尽管它们对于快速方法似乎更一致。这尤其奇怪,因为我在总结每次测试中创建的多个列表的结果

itertools的引擎盖下发生了什么?我们如何解释这些计时结果?尤其奇怪的是,
链接的方式。from_iterable
repeat
在这里不提供增量性能优势,而是完全相互依赖。列表的构建是怎么回事?在每种情况下增加的开销是不是都是一样的(重复地将相同的元素序列附加到一个空列表中)?

它主要归结为花在解释器中的时间量的大O

  • 解释器中没有循环允许C函数直接通信。
    • 但是嵌套如此多的itertools会增加很小但可以测量的开销。
      • I
        在下表中
  • 一个循环仅为少数操作码的×1000
  • 嵌套循环的数量高达1000000个
  • 直接从
    repeat
    屈服比屈服前从
    range
    存储短一些操作码。
    • Y
      在下表中
  • explicit
    generator
    实际上是等效的
  • 嵌套生成器是一种嵌套函数调用-代价高昂。
    • G
      在下表中
以下是我的结果:

方法 复杂性(仅限解释器) 列表 消费 工具
O(0)+I
0.21 0.09 工具之星
O(0)+I
0.21 0.09 混合的
O(N)
0.20 0.09 混合2
O(N²)
0.54 0.47 明确的
O(N²)+Y
0.64 0.60 发电机
O(N²)+Y
0.64 0.60 工具
O(N²)+G
0.71 0.65
时间变化很可能来自不相关的进程,例如malloc内部或操作系统调度。在我的机器上,输入的是2%的倍数,你的看起来很相似。