将迭代器传递给 any 来执行以提高速度,为什么?

2024-02-28

问题总结如下。是的,我知道some这些答案;)我可以向其他人挥手致意,但我真的很想在这里了解实质内容。

  1. 这到底是个好主意吗? (这个是not below)
  2. 我想知道地图是否真的增加了速度提升?为什么?
  3. 为什么要将迭代器传递给any http://docs.python.org/library/functions.html#any让我的代码更快?
  4. 为什么我的 Counter 对象可以工作,而 print_true 函数却严重失败?
  5. 有没有相当于迭代工具.imap http://docs.python.org/library/itertools.html#itertools.imap这只会一遍又一遍地调用一个函数,并且可以选择调用一定的次数?
  6. 我的胡萝卜在哪里?!?

我刚刚看了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...

注意:我鼓励您自己运行测试。


在你的第一个例子中,第一个版本run必须抬头_md5.update每次都循环,而第二个版本则不然。我想您会发现这是造成大部分性能差异的原因。剩下的可能与设置局部变量有关i,尽管这并不容易证明。

import itertools, hashlib, timeit
_md5 = hashlib.md5()

def run1():
    for i in itertools.repeat("foo", 10000000):
        _md5.update(i)

def run2():
    u = _md5.update
    for i in itertools.repeat("foo", 10000000):
        u(i)

def run3():
    any(itertools.imap(_md5.update, itertools.repeat("foo", 10000000)))

>>> timeit.timeit('run1()', 'from __main__ import run1', number=1)
6.081272840499878
>>> timeit.timeit('run2()', 'from __main__ import run2', number=1)
4.660238981246948
>>> timeit.timeit('run3()', 'from __main__ import run3', number=1)
4.062871932983398

The itertools documentation http://docs.python.org/library/itertools.html#recipes has a better recipe for consuming an iterator (and discarding all its values): see the consume function. The use of any to do this job depends on the fact that _md5.update always returns None, so this approach doesn't work in general. Also, the recipe is very slightly faster: [see comments]

import collections

def consume(it):
    "Consume iterator completely (discarding its values)."
    collections.deque(it, maxlen=0)

def run4():
    consume(itertools.imap(_md5.update, itertools.repeat("foo", 10000000)))

>>> timeit.timeit('run4()', 'from __main__ import run4', number=1)
3.969902992248535

编辑添加:看来consume配方并不像应有的那样广为人知:如果您查看 CPython 实现的详细信息,您会发现当collections.deque被称为maxlen=0然后它调用该函数consume_iterator in _collectionsmodule.c http://hg.python.org/cpython/file/fd424ccc8cee/Modules/_collectionsmodule.c#l280,看起来像这样:

static PyObject*
consume_iterator(PyObject *it)
{
    PyObject *item;
    while ((item = PyIter_Next(it)) != NULL) {
        Py_DECREF(item);
    }
    Py_DECREF(it);
    if (PyErr_Occurred())
        return NULL;
    Py_RETURN_NONE;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将迭代器传递给 any 来执行以提高速度,为什么? 的相关文章

随机推荐

  • 某些设备在下班后收到 Gcm 通知

    我正在尝试使用 gcm 通知 我的服务器代码工作正常 并且我获得了成功作为确认 问题是通知发送正确 1 在大多数设备中 通知是立即收到的 在谷歌 Nexus 索尼手机上测试 2 其他设备也在几个小时后收到通知 是的 hours 在 Karb
  • Swift:IAP 更新交易未在 .Purchased 上调用

    我的代码有问题 updateTransactions 函数仅在交易进行时调用一次 交易完成后不再调用 func buyProduct product SKProduct let payment SKPayment product produ
  • Python PyQt - QTableWidget、JSON 和 emitSignal 导致空白单元格

    我将 PyQt 用于一个简单的应用程序 该应用程序从包含 JSON 格式字符串的日志文件中读取数据 并将它们很好地输出到表中 一切都按预期工作 除非我尝试从 加载 函数发出信号 该信号由主窗口拾取 位于一个设计为用新信息重新排列表的槽中 如
  • Lucene TermQuery 和 QueryParser

    我有 2 个 lucene 查询 1 Term term new Term Properties LUCENE APPARTMENT ADDRESS address Query termQuery new TermQuery term To
  • Flutter showDialog 未在 PopupMenuItem 点击上显示

    我在用着PopupMenuButton在我的应用程序中 我想要showDialog在点击一个PopupMenuItem My PopupMenuItem PopupMenuItem child Text Show dialog onTap
  • setState 方法导致 Reactjs 函数中的结果无限循环

    该代码显示数组中的用户记录 我还创建了一个updateCount 功能对内容显示的用户进行计数 我可以看到计数结果alerted并在控制台中 现在我想显示计数结果 为此 我初始化setState 内的方法updateCount功能 upda
  • PHP 和 Java 中的 SHA256

    我正在将一些 Java 代码移植到 PHP 代码 在Java中我有一个哈希SHA256代码如下 public static String hashSHA256 String input throws NoSuchAlgorithmExcep
  • 从 Action 指令创建 DynamicMethod

    我正在使用 DynamicMethod 并旨在执行以下操作 我有一个 Action 从中可以使用字节形式获取 IL 代码GetILAsByteArray 从这个字节我想创建一个动态方法并执行 这是我正在尝试做的事情的一个例子 class P
  • 在 Windows 10 上使用 nuwen MinGW 的 C++17 文件系统

    我想尝试 C 17 中的新文件系统库 因此尝试复制来自 cppreference com 的 std filesystem current path 示例 https en cppreference com w cpp filesystem
  • PDO 语句会自动转义吗?

    PHP PDO 语句是自动转义的 还是仅准备好的语句 例如 假设 username and password是用户输入 以下代码是否安全 或者是否容易受到注入 dbh new PDO mysql host localhost dbname
  • 在 std::wstring 中查找方法

    我已声明Wstring如下 wstring strID 当我尝试查找出现的子字符串时 如下所示 int index strID find LABS 我收到如下错误 error C2664 unsigned int std basic str
  • 如何在 python 中使用可变宽度高斯函数执行卷积?

    我需要使用高斯执行卷积 但是高斯的宽度需要改变 我不进行传统的信号处理 而是需要根据设备的分辨率获取完美的概率密度函数 PDF 并 涂抹 它 例如 假设我的 PDF 一开始是尖峰 增量函数 我将其建模为非常窄的高斯 经过我的设备运行后 它将
  • Spring中如何只实现CrudRepository的特定方法?

    我在用着CrudRepositoryspring data jpa 只定义一个实体的接口 然后拥有所有标准的 CRUD 方法 而无需显式提供实现 例如 public interface UserRepo extends CrudReposi
  • 批量插入问题

    我在客户端有一个 CSV 文件 我想开发一个 C 应用程序来将数据批量插入到数据库的表中 以尽量减少日志输出 我对是否在客户端使用 ADO NET 调用数据库服务器中的存储过程感到困惑 什么样的代码需要在客户端开发 什么样的代码需要在服务器
  • 如何在快速路线中调用不同的 REST API?

    我有一个使用多种路由创建的express js REST API 我想创建一个路由来调用另一个 REST API 然后返回结果 理想情况下 它应该类似于以下内容 router post CreateTicket cors corsOptio
  • UIImagePickerController - 相机未准备好

    我正在开发一个录制视频的 iPhone 应用程序 我创建一个 UIImagePickerController 将其限制为视频录制 然后以编程方式要求相机启动VideoCapture 不幸的是 当我运行该应用程序时 我在控制台中看到以下内容
  • 为什么我无法使用 python 建立与rabbitMQ的连接?

    我正在学习如何使用rabbitMQ 我正在 MacBook 上运行rabbit MQ 服务器并尝试与 python 客户端连接 我按照安装说明进行操作here http www rabbitmq com install homebrew h
  • DynamoDB - 新放入的项目未反映在扫描中

    我在 DynamoDB 扫描方面遇到问题 我使用以下命令将新项目添加到表中putItem method AmazonClientManager ddb putItem request 但是 当我尝试使用扫描方法进行扫描时 该项目不会出现在结
  • 如果 xmlcharrefreplace 和 backslashreplace 不起作用,我应该如何解码字节(使用 ASCII)而不丢失任何“垃圾”字节?

    我有一个网络资源 它返回给我的数据 根据规范 应该是 ASCII 编码的字符串 但在极少数情况下 我会收到垃圾数据 例如返回一种资源b xd3PS 90AC 而另一个资源 对于相同的键返回b PS 90AC 第一个值包含非 ASCII 字符
  • 将迭代器传递给 any 来执行以提高速度,为什么?

    问题总结如下 是的 我知道some这些答案 我可以向其他人挥手致意 但我真的很想在这里了解实质内容 这到底是个好主意吗 这个是not below 我想知道地图是否真的增加了速度提升 为什么 为什么要将迭代器传递给any http docs