Der*_*itz 5 python performance
这里总结了一些问题.是的,我知道其中一些答案;)我可以在其他人身上挥手,但我真的很喜欢这里的细节.
我只是看着PYCON 2011:Dropbox的是怎么做的和如何Python的帮助了(当然我完成大部分的零件跳过),但最后真正有趣的东西开始在大约22:23.
演讲者主张在C中制作你的内部循环并且"运行一次"的东西不需要太多的优化(有意义)......然后他继续陈述......释义:
将迭代器的组合传递给任何用于大规模速度改进的组合.
这是代码(希望它是相同的):
import itertools, hashlib, time
_md5 = hashlib.md5()
def run():
for i in itertools.repeat("foo", 10000000):
_md5.update(i)
a = time.time(); run(); time.time() - a
Out[118]: 9.44077205657959
_md5 = hashlib.md5()
def run():
any(itertools.imap(_md5.update, itertools.repeat("foo", 10000000)))
a = time.time(); run(); time.time() - a
Out[121]: 6.547091007232666
Run Code Online (Sandbox Code Playgroud)
嗯,看起来更高的速度改进,我可以得到一个更快的电脑!(从他的幻灯片来看.)
然后他做了一堆挥手而没有真正详细说明为什么.
我已经知道迭代器从回答pythonic方式做N次而没有索引变量?感谢Alex Martelli.
然后我想,我想知道地图是否真的增加了速度提升?我最后的想法是WTF ??? 传递到任何?真???当然,因为文档定义了不能正确任何为:
def any(iterable):
for element in iterable:
if element:
return True
return False
Run Code Online (Sandbox Code Playgroud)
为什么世界上会将迭代器传递给任何使代码更快的代码呢?
然后,我使用以下(在许多其他测试中)测试它,但这是让我:
def print_true(x):
print 'True'
return 'Awesome'
def test_for_loop_over_iter_map_over_iter_repeat():
for result in itertools.imap(print_true, itertools.repeat("foo", 5)):
pass
def run_any_over_iter_map_over_iter_repeat():
any(itertools.imap(print_true, itertools.repeat("foo", 5)))
And the runs:
In [67]: test_for_loop_over_iter_map_over_iter_repeat()
True
True
True
True
True
In [74]: run_any_over_iter_map_over_iter_repeat()
True
Run Code Online (Sandbox Code Playgroud)
耻辱.我宣布这个GUY是完全的. 异教徒!但是,我平静下来并继续测试. 如果这是真的,Dropbox甚至可以在地狱工作!?!?
通过进一步的测试,它确实有用......我最初只使用了一个简单的计数器对象,在这两种情况下它都计数到10000000.
所以问题是为什么我的Counter对象工作并且我的print_true函数失败了?
class Counter(object):
count = 0
def count_one(self, none):
self.count += 1
def run_any_counter():
counter = Counter()
any(itertools.imap(counter.count_one, itertools.repeat("foo", 10000000)))
print counter.count
def run_for_counter():
counter = Counter()
for result in itertools.imap(counter.count_one, itertools.repeat("foo", 10000000)):
pass
print counter.count
Run Code Online (Sandbox Code Playgroud)
输出:
%time run_for_counter()
10000000
CPU times: user 5.54 s, sys: 0.03 s, total: 5.57 s
Wall time: 5.68 s
%time run_any_counter()
10000000
CPU times: user 5.28 s, sys: 0.02 s, total: 5.30 s
Wall time: 5.40 s
Run Code Online (Sandbox Code Playgroud)
甚至更大的WTF甚至在删除不需要的参数并为我的Counter对象编写最合理的代码之后,它仍然比任何地图版本慢.我的胡萝卜在哪里?!?:
class CounterNoArg(object):
count = 0
def count_one(self):
self.count += 1
def straight_count():
counter = CounterNoArg()
for _ in itertools.repeat(None, 10000000):
counter.count_one()
print counter.count
Run Code Online (Sandbox Code Playgroud)
输出继电器:
In [111]: %time straight_count()
10000000
CPU times: user 5.44 s, sys: 0.02 s, total: 5.46 s
Wall time: 5.60 s
Run Code Online (Sandbox Code Playgroud)
我问,因为我认为Pythonistas或Pythoneers需要一个胡萝卜,所以我们不会开始将内容传递给任何或所有的性能提升,还是已经存在?可能是itertools.imap的等价物,它会一次又一次地调用一个函数,并且可选地调用一定次数.
我管理的最好的是(使用列表理解给出了有趣的结果):
def super_run():
counter = CounterNoArg()
for _ in (call() for call in itertools.repeat(counter.count_one, 10000000)):
pass
print counter.count
def super_counter_run():
counter = CounterNoArg()
[call() for call in itertools.repeat(counter.count_one, 10000000)]
print counter.count
def run_any_counter():
counter = Counter()
any(itertools.imap(counter.count_one, itertools.repeat("foo", 10000000)))
print counter.count
%time super_run()
10000000
CPU times: user 5.23 s, sys: 0.03 s, total: 5.26 s
Wall time: 5.43 s
%time super_counter_run()
10000000
CPU times: user 4.75 s, sys: 0.18 s, total: 4.94 s
Wall time: 5.80 s
%time run_any_counter()
10000000
CPU times: user 5.15 s, sys: 0.06 s, total: 5.21 s
Wall time: 5.30 s
def run_any_like_presentation():
any(itertools.imap(_md5.update, itertools.repeat("foo", 10000000)))
def super_run_like_presentation():
[do_work for do_work in itertools.imap(_md5.update, itertools.repeat("foo", 10000000))]
def super_run_like_presentation_2():
[_md5.update(foo) for foo in itertools.repeat("foo", 10000000)]
%time run_any_like_presentation()
CPU times: user 5.28 s, sys: 0.02 s, total: 5.29 s
Wall time: 5.47 s
%time super_run_like_presentation()
CPU times: user 6.14 s, sys: 0.18 s, total: 6.33 s
Wall time: 7.56 s
%time super_run_like_presentation_2()
CPU times: user 8.44 s, sys: 0.22 s, total: 8.66 s
Wall time: 9.59 s
Run Code Online (Sandbox Code Playgroud)
啊...
注意:我鼓励您自己运行测试.