【问题标题】:Python: slow nested for loopPython:慢速嵌套 for 循环
【发布时间】:2016-09-19 08:57:09
【问题描述】:

我需要根据某些限制条件找出最佳的媒体选择。我在四个嵌套的 for 循环中执行此操作,因为它需要大约 O(n^4) 次迭代,所以速度很慢。我一直试图让它更快,但它仍然很慢。我的变量可能高达几千。

这是我正在尝试做的一个小例子:

    max_disks = 5
    max_ssds = 5
    max_tapes = 1
    max_BR    = 1
    allocations = []
    for i in range(max_disks):
     for j in range(max_ssds):
        for k in range(max_tapes):
            for l in range(max_BR):
                allocations.append((i,j,k,l)) # this is just for example. In actual program, I do processing here, like checking for bandwidth and cost constraints, and choosing the allocation based on that. 

每种媒体类型多达数百个并不慢,但会减慢数千个。

我试过的其他方法是:

    max_disks = 5
    max_ssds = 5
    max_tapes = 1
    max_BR    = 1

    allocations = [(i,j,k,l) for i in range(max_disks) for j in range(max_ssds) for k in range(max_tapes) for l in range(max_BR)]

这样即使是这么小的数字也很慢。

两个问题:

  1. 为什么第二个对于小数字来说很慢?
  2. 如何使我的程序适用于大数字(以千计)?

这是带有 itertools.product 的版本

            max_disks = 500
            max_ssds = 100
            max_tapes = 100
            max_BR    = 100
            # allocations = []
            for i, j, k,l in itertools.product(range(max_disks),range(max_ssds),range(max_tapes),range(max_BR)):
                pass

完成这些数字需要 19.8 秒。

【问题讨论】:

  • 第一个具有列表理解的示例比第二个示例。它们在其他方面是等效的,但allocations.append 属性查找和后续方法调用会减慢嵌套循环。您可能想在这里查看itertools.product(),并避免使用所有可能的组合创建一个巨大的列表对象(而是一个一个地处理项目)。
  • 我也试过 itertools.product() 。但这对数千人也不起作用。
  • 你坚持要建立一个分配列表吗?您已经知道要构建的列表的一般结构,所以您不能单独处理分配吗?
  • 添加到我在这里使用的列表中只是一个例子。实际上,在最里面的循环中,我正在执行诸如检查分配提供的带宽之类的操作,并决定是否保留分配。
  • @Pretty: '没用' 但是什么也没告诉我们。 itertools.product() 仍然比您发布的任何一种方法都快,并且如果您不首先将所有内容都具体化到列表中,那么它是无与伦比的。也许您想展示还有什么您正在使用您生成的组合做什么?为什么首先需要在列表中生成这么多的元组?

标签: python performance linear-programming constraint-programming


【解决方案1】:

从 cmets 得知,您正在解决一个可以重写为 ILP 的问题。您有几个限制条件,需要找到(接近)最优解。

现在,ILP 非常难以解决,并且暴力破解它们很快变得难以处理(正如您已经看到的那样)。这就是为什么业界使用了几种真正具有魔力的非常聪明的算法。

对于 Python,有很多接口可以连接到现代求解器;有关更多详细信息,请参阅例如SO post。您也可以考虑使用优化器,例如 SciPy optimize,但它们通常不进行整数规划。

【讨论】:

    【解决方案2】:

    在 Python 中执行任何操作一万亿次都会很慢。然而,这并不是你所做的全部。通过尝试将所有万亿项存储在一个列表中,您将大量数据存储在内存中并以一种为计算机创建大量工作以在内存不再适合 RAM 时交换内存的方式进行操作。

    Python 列表的工作方式是分配一些内存来存储列表中的项目。当你填满列表并且它需要分配更多时,Python 将分配两倍的内存并将所有旧条目复制到新的存储空间中。只要它适合内存就可以了 - 即使它每次扩展存储时都必须复制列表的所有内容,但它必须不那么频繁地这样做,因为它会不断增加两倍的大小。当它耗尽内存并且必须将未使用的内存交换到磁盘时,就会出现问题。下次它尝试调整列表大小时,它必须从磁盘重新加载所有现在已换出到磁盘的条目,然后再次将它们全部换出以获取空间来写入新条目。因此,这会产生大量缓慢的磁盘操作,这些操作会妨碍您的任务并进一步减慢它的速度。

    您真的需要将每个项目都存储在列表中吗?完成后你打算如何处理它们?您也许可以在进行时将它们写入磁盘,而不是将它们累积在一个巨大的列表中,尽管如果您拥有一万亿个它们,那仍然是非常大量的数据!或者也许你正在过滤掉其中的大部分?这会有所帮助。

    说了这么多,如果没有看到实际的程序本身,很难知道您是否有希望通过详尽的搜索来完成这项工作。所有变量都可以同时达到数千个吗?你真的需要考虑这些变量的每一个组合吗?当 max_disks==2000 时,你真的需要区分 i=1731 和 i=1732 的结果吗?例如,也许您可​​以考虑 i 的值 1,2,3,4,5,10,20,30,40,50,100,200,300,500,1000,2000?或者也许有一个数学解决方案?你只是在数物品吗?

    【讨论】:

      猜你喜欢
      • 2021-04-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多