问题总结如下。是的,我知道some这些答案;)我可以向其他人挥手致意,但我真的很想在这里了解实质内容。
- 这到底是个好主意吗? (这个是not below)
- 我想知道地图是否真的增加了速度提升?为什么?
- 为什么要将迭代器传递给any http://docs.python.org/library/functions.html#any让我的代码更快?
- 为什么我的 Counter 对象可以工作,而 print_true 函数却严重失败?
- 有没有相当于迭代工具.imap http://docs.python.org/library/itertools.html#itertools.imap这只会一遍又一遍地调用一个函数,并且可以选择调用一定的次数?
- 我的胡萝卜在哪里?!?
我刚刚看了PyCon 2011:Dropbox 是如何做到的以及 Python 如何提供帮助 http://blip.tv/pycon-us-videos-2009-2010-2011/pycon-2011-how-dropbox-did-it-and-how-python-helped-4896698#disqus_thread(诚然,我跳过了大部分内容),但真正有趣的内容终于在 22:23 左右开始了。
演讲者主张用 C 语言制作内部循环,并且“运行一次”的东西不需要太多优化(有意义)……然后他继续陈述……解释一下:
将迭代器的组合传递给any http://docs.python.org/library/functions.html#any大幅提高速度。
这是代码(希望是相同的):
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
嗯,看起来为了更大的速度提升,我可以买一台更快的计算机! (从他的幻灯片来看。)
然后他挥了挥手,但没有真正详细说明why.
我已经从答案中了解了迭代器pythonic 方法在没有索引变量的情况下执行 N 次某事? https://stackoverflow.com/questions/2970780/pythonic-way-to-do-something-n-times感谢亚历克斯·马尔泰利。
然后我想,我想知道地图是否真的增加了速度提升?我最后的想法是 WTF???传递到any http://docs.python.org/library/functions.html#any?真的吗???这肯定是不对的,因为文档定义了any http://docs.python.org/library/functions.html#any as:
def any(iterable):
for element in iterable:
if element:
return True
return False
为什么将迭代器传递给any 会使我的代码更快?
然后我使用以下内容(以及许多其他测试)对其进行了测试,但这就是让我感兴趣的:
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
耻辱。我宣称这个家伙充满了它。Heretic!不过,我冷静下来,继续测试。如果这是真的,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
output:
%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
更糟糕的是,即使删除了不需要的参数并为我的 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
Ouput:
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
我这么问是因为我认为 Pythonistas 或 Pythoneers 需要一根胡萝卜,这样我们就不会开始向他们传递东西any http://docs.python.org/library/functions.html#any or all http://docs.python.org/library/functions.html#all是为了提高性能,还是已经存在?可能相当于迭代工具.imap http://docs.python.org/library/itertools.html#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
Ugh...
注意:我鼓励您自己运行测试。