Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/345.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.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
Python3.5和3.6是什么使;“地图”;比理解慢_Python_Performance_Python 3.5_Python 3.6_Cpython - Fatal编程技术网

Python3.5和3.6是什么使;“地图”;比理解慢

Python3.5和3.6是什么使;“地图”;比理解慢,python,performance,python-3.5,python-3.6,cpython,Python,Performance,Python 3.5,Python 3.6,Cpython,如果有一个函数/方法是用C编写的,我有时会使用map,以获得一些额外的性能。然而,我最近重新审视了一些基准测试,并注意到在Python 3.5和3.6之间,相对性能(与类似的列表理解相比)发生了巨大的变化 这不是实际的代码,只是一个说明差异的最小示例: import random lst = [random.randint(0, 10) for _ in range(100000)] assert list(map((5).__lt__, lst)) == [5 < i for i in

如果有一个函数/方法是用C编写的,我有时会使用
map
,以获得一些额外的性能。然而,我最近重新审视了一些基准测试,并注意到在Python 3.5和3.6之间,相对性能(与类似的列表理解相比)发生了巨大的变化

这不是实际的代码,只是一个说明差异的最小示例:

import random

lst = [random.randint(0, 10) for _ in range(100000)]
assert list(map((5).__lt__, lst)) == [5 < i for i in lst]
%timeit list(map((5).__lt__, lst))
%timeit [5 < i for i in lst]
虽然Python-3.6计时实际上表明理解速度更快:

17.9 ms ± 755 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
14.3 ms ± 128 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

我的问题是,在这种情况下发生了什么,使得列表理解更快,
map
解决方案更慢?我意识到差异并没有那么大,这只是让我好奇,因为这是我有时(实际上很少)在性能关键代码中使用的“技巧”之一。

我认为公平的比较应该包括使用相同的函数。在您的示例中,当比较公平时,
map
仍然获胜:

>>> import sys
>>> print(sys.version)
3.6.2 |Continuum Analytics, Inc.| (default, Jul 20 2017, 13:14:59) 
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.57)]
>>> import random
>>> lst = [random.randint(0, 10) for _ in range(100000)]
>>> assert list(map((5).__lt__, lst)) == [5 < i for i in lst]
>>> f = (5).__lt__
>>> %timeit list(map(f, lst))
4.63 ms ± 110 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
>>> %timeit [f(i) for i in lst]
9.17 ms ± 177 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
但是,在使用相同的函数时,
map
比Python 3.5和3.6中的列表理解速度快约2倍

编辑(回复@user2357112评论): 我认为,在回答OP的问题时,进行“公平”比较是很重要的:“我的问题是,在这种情况下发生了什么,使得列表理解更快,map解决方案更慢?”(最后一段)。然而,在第一段中,@MSeifert说:“…[I]注意到Python 3.5和3.6之间的相对性能(与类似的列表理解相比)发生了巨大变化”,也就是说,比较是在
映射
列表理解
之间进行的。然而,@MSeifert测试设置如下:

timig_map_35 = Timing(list(map(f, lst)))
timing_list_35 = Timing([g(i) for i in lst])
这种测试很难找到时间差异的原因:是因为3.6中的列表理解速度变快,还是3.6中的map速度变慢,还是3.6中的
f(i)
速度变慢,还是
g(i)
速度变快

因此,我建议引入
f=(5)。\uu lt\uuu
并在
map
和list理解测试中使用相同的函数。我还修改了@MSeifert测试,增加了列表中的元素数量,并减少了
timeit
中的“循环”数量:

import random
lst = [random.randint(0, 10) for _ in range(1000000)] # 10x more elements
f = (5).__lt__
%timeit -n1 -r1000 list(map(f, lst)) # f = (5).__lt__
%timeit -n1 -r1000 [f(i) for i in lst] # f(i) = (5).__lt__(i)
%timeit -n1 -r1000 [5 < i for i in lst] # g(i) = 5 < i
%timeit -n1 -r1000 [1 for _ in lst] # h(i) = 1
在Python 3.5中,我得到:

1 loop, best of 1000: 43.7 ms per loop
1 loop, best of 1000: 78.9 ms per loop
1 loop, best of 1000: 46 ms per loop
1 loop, best of 1000: 26.8 ms per loop
1 loop, best of 1000: 38.3 ms per loop
1 loop, best of 1000: 56.4 ms per loop
1000000 loops, best of 1000: 59.6 ns per loop
在我看来,这表明3.6中的列表理解略快于3.5,除非使用
f
。因此,很难断定是
map
在Python3.6中较慢,还是第一个
timeit
较慢,因为对
f
的调用较慢。因此,我又进行了两次测试:

%timeit -n1 -r1000 list(map(abs, lst))
%timeit -n1 -r1000 [abs(i) for i in lst]
%timeit -n1000000 -r1000 f(1)
在Python 3.6中,我得到:

43.5 ms ± 1.79 ms per loop (mean ± std. dev. of 1000 runs, 1 loop each)
82.2 ms ± 2.39 ms per loop (mean ± std. dev. of 1000 runs, 1 loop each)
43.6 ms ± 1.64 ms per loop (mean ± std. dev. of 1000 runs, 1 loop each)
23.8 ms ± 1.27 ms per loop (mean ± std. dev. of 1000 runs, 1 loop each)
25.8 ms ± 1.42 ms per loop (mean ± std. dev. of 1000 runs, 1 loop each)
67.1 ms ± 2.07 ms per loop (mean ± std. dev. of 1000 runs, 1 loop each)
64.7 ns ± 2.22 ns per loop (mean ± std. dev. of 1000 runs, 1000000 loops each)
在Python 3.5中,我得到:

1 loop, best of 1000: 43.7 ms per loop
1 loop, best of 1000: 78.9 ms per loop
1 loop, best of 1000: 46 ms per loop
1 loop, best of 1000: 26.8 ms per loop
1 loop, best of 1000: 38.3 ms per loop
1 loop, best of 1000: 56.4 ms per loop
1000000 loops, best of 1000: 59.6 ns per loop
这表明,对于某些函数,
map
可以大大快于列表理解:具体来说,对于
abs(x)
来说,
map
与Python3.6中的“列表理解”的相对性能是
67.1/25.8=2.60
,而在Python3.5中是
56.4/38.3=1.47
。因此,了解@MSeifert测试显示Python 3.6中
map
速度较慢的原因很有意思。我上面的最后一个测试显示了
f(1)
“单独”的定时测试。我不确定这个测试有多有效(不幸的是)-我想避免使用
map
[for]
来消除一个变量-但它表明在Python3.6中
f=(5)。\uu lt\uuuu
变得比Python3.5慢。因此,我得出结论,是函数
f
(5)。\uuu lt\uuu
)的特定形式的计算速度变慢了,而不是
map
函数。我知道最后的“单独”测试可能是一个糟糕的测试,但是,当与
abs
一起使用时,
map
速度非常快(相对或绝对)这一事实表明问题出在
f
而不是
map


注意:Python 3.5使用IPython 5.3.0,Python 3.6使用IPython 6.1.0。

我认为公平的比较包括在Python 3.5和3.6中使用相同的函数和相同的测试条件,以及在比较
map
以列出所选Python版本中的理解

在我最初的回答中,我进行了多次测试,结果表明,与列表理解相比,
map
在两个版本的Python中都要快两倍。然而,一些结果并不是决定性的,所以我进行了更多的测试

首先,让我列举你在问题中提出的一些观点:

“…[I]注意到,
map
]的相对性能(与类似的列表理解相比)在Python 3.5和3.6之间发生了显著的变化。”

你还问:

“我的问题是,在这种情况下发生了什么,使得列表理解更快,地图解决方案更慢?”

不太清楚的是,在Python3.6中,map的速度比列表理解慢,还是Python3.6中map的速度比3.5慢,并且列表理解的性能提高了(尽管不一定达到了打败
map
的水平)

根据我在第一次回答这个问题后进行的更广泛的测试,我想我对正在发生的事情有了一个想法

然而,首先让我们为“公平”比较创造条件。为此,我们需要:

  • 比较
    map
    在使用相同函数的不同Python版本中的性能

  • 比较
    map
    的性能,以使用相同功能在同一版本中列出理解

  • 在相同的数据上运行测试

  • 最小化定时功能的影响

  • 以下是有关我的系统的版本信息:

    Python 3.5.3 |Continuum Analytics, Inc.| (default, Mar  6 2017, 12:15:08) 
    [GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.57)] on darwin
    IPython 5.3.0 -- An enhanced Interactive Python.
    

    让我们首先讨论“相同数据”的问题。不幸的是,因为您有效地使用了
    seed(None)
    ,所以两个版本的Python上的每个数据集
    lst
    都是不同的。这
    Python 3.6.2 |Continuum Analytics, Inc.| (default, Jul 20 2017, 13:14:59) 
    [GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.57)] on darwin
    IPython 6.1.0 -- An enhanced Interactive Python. Type '?' for help.
    
    import numpy as np
    import random
    lst = [random.randint(0, 10) for _ in range(100000000)]
    np.save('lst', lst, allow_pickle=False)
    
    In [11]: f = (5).__lt__
    In [12]: %timeit -n1 -r20 [f(i) for i in lst]
    1 loop, best of 20: 9.01 s per loop
    
    >>> t = timeit.repeat('[f(i) for i in lst]', setup="f = (5).__lt__;
    ... import numpy; lst = numpy.load('lst.npy').tolist()", repeat=20, 
    ... number=1); print(min(t), max(t), np.mean(t), np.std(t))
    7.442819457995938 7.703615028003696 7.5105415405 0.0550515642854
    
    >>> import numpy as np
    >>> import timeit
    
    >>> t = timeit.repeat('list(map(f, lst))', setup="f = (5).__lt__; import numpy; lst = numpy.load('lst.npy').tolist()", repeat=20, number=1); print(min(t), max(t), np.mean(t), np.std(t))
    4.666553302988177 4.811194089008495 4.72791638025 0.041115884397
    
    >>> t = timeit.repeat('[f(i) for i in lst]', setup="f = (5).__lt__; import numpy; lst = numpy.load('lst.npy').tolist()", repeat=20, number=1); print(min(t), max(t), np.mean(t), np.std(t))
    7.442819457995938 7.703615028003696 7.5105415405 0.0550515642854
    
    >>> t = timeit.repeat('[5 < i for i in lst]', setup="import numpy; lst = numpy.load('lst.npy').tolist()", repeat=20, number=1); print(min(t), max(t), np.mean(t), np.std(t))
    4.94656751700677 5.07807950800634 5.00670203845 0.0340474956945
    
    >>> t = timeit.repeat('list(map(abs, lst))', setup="import numpy; lst = numpy.load('lst.npy').tolist()", repeat=20, number=1); print(min(t), max(t), np.mean(t), np.std(t))
    4.167273573024431 4.320013975986512 4.2408865186 0.0378852782878
    
    >>> t = timeit.repeat('[abs(i) for i in lst]', setup="import numpy; lst = numpy.load('lst.npy').tolist()", repeat=20, number=1); print(min(t), max(t), np.mean(t), np.std(t))
    5.664627838006709 5.837686392012984 5.71560354655 0.0456700607748
    
    >>> t = timeit.repeat('f(1)', setup="f = (5).__lt__", repeat=20, number=1000000); print(min(t), max(t), np.mean(t), np.std(t))
    0.052280781004810706 0.05500587198184803 0.0531139718529 0.000877649561967
    
    >>> t = timeit.repeat('5 < 1', repeat=20, number=1000000); print(min(t), max(t), np.mean(t), np.std(t))
    0.030931947025237605 0.033691533986711875 0.0314959864045 0.000633274658428
    
    >>> t = timeit.repeat('abs(1)', repeat=20, number=1000000); print(min(t), max(t), np.mean(t), np.std(t))
    0.04685414198320359 0.05405496899038553 0.0483296330043 0.00162837880358
    
    >>> import numpy as np
    >>> import timeit
    
    >>> t = timeit.repeat('list(map(f, lst))', setup="f = (5).__lt__; import numpy; lst = numpy.load('lst.npy').tolist()", repeat=20, number=1); print(min(t), max(t), np.mean(t), np.std(t))
    4.599696700985078 4.743880658003036 4.6631793691 0.0425774678203
    
    >>> t = timeit.repeat('[f(i) for i in lst]', setup="f = (5).__lt__; import numpy; lst = numpy.load('lst.npy').tolist()", repeat=20, number=1); print(min(t), max(t), np.mean(t), np.std(t))
    7.316072431014618 7.572676292009419 7.3837024617 0.0574811241553
    
    >>> t = timeit.repeat('[5 < i for i in lst]', setup="import numpy; lst = numpy.load('lst.npy').tolist()", repeat=20, number=1); print(min(t), max(t), np.mean(t), np.std(t))
    4.570452399988426 4.679144663008628 4.61264215875 0.0265541828693
    
    >>> t = timeit.repeat('list(map(abs, lst))', setup="import numpy; lst = numpy.load('lst.npy').tolist()", repeat=20, number=1); print(min(t), max(t), np.mean(t), np.std(t))
    2.742673939006636 2.8282236389932223 2.78504617405 0.0260357089928
    
    >>> t = timeit.repeat('[abs(i) for i in lst]', setup="import numpy; lst = numpy.load('lst.npy').tolist()", repeat=20, number=1); print(min(t), max(t), np.mean(t), np.std(t))
    6.2177103200228885 6.428813881997485 6.28722427145 0.0493010620999
    
    >>> t = timeit.repeat('f(1)', setup="f = (5).__lt__", repeat=20, number=1000000); print(min(t), max(t), np.mean(t), np.std(t))
    0.051936342992121354 0.05764096099301241 0.0532974587506 0.00117079475737
    
    >>> t = timeit.repeat('5 < 1', repeat=20, number=1000000); print(min(t), max(t), np.mean(t), np.std(t))
    0.02675032999832183 0.032919151999522 0.0285137565021 0.00156522182488
    
    >>> t = timeit.repeat('abs(1)', repeat=20, number=1000000); print(min(t), max(t), np.mean(t), np.std(t))
    0.047831349016632885 0.0531779529992491 0.0482893927969 0.00112825297875