我正在使用这样的算法对Decimals数组进行一些计算:
fkn = Decimal('0')
for bits in itertools.combinations(decimals_array, elements_count):
kxn = reduce(operator.mul, bits, Decimal('1'))
fkn += kxn
我使用的是Python 3.4 x64。 小数的精度> 300(必须)。 len(decimals_array)大部分时间都超过40。 elements_count大部分时间是len(decimals_array)/ 2。
计算需要很长时间。 我想让它们成为多进程,所以首先我考虑制作一个包含所有组合的数组并将这个数组的一部分发送到许多进程 - 但是在制作这样的数组时我很快就会得到MemoryError异常。
现在我正在寻找更好的方法来使这个代码成为多进程。
在多个核心上运行此算法的好方法是什么?
或许有更好(更快)的方法进行此类计算?
提前感谢你提出一些想法。
答案 0 :(得分:1)
为了真正实现此并行化,您需要让combinations()
顺序进行,以便每个进程都可以生成自己的组合。问题的其余部分已经可以解释了。
40选择20是大约1380亿个组合,因此预先生成或在每个过程中生成它会受到伤害。如果你一次性生成整个东西,那么20个元素的列表大约需要224个字节(表示sys.getsizeof()
),那就是30兆兆字节。难怪你的内存不足。您也无法跨进程真正拆分生成器;或者更确切地说,如果你这样做,每个进程都将获得自己的生成器副本。
解决方案1是拥有一个进程,其唯一的工作是生成组合并将它们推送到队列中,可能是批量存储以节省IPC开销,并使其他进程使用该队列中的组合。
解决方案2是编写combinations
的非顺序版本,返回第N个组合而不计算其余部分。这绝对是可能的,因为它可能具有排列,并且组合是排列的内部排序子集。然后Pool
中的每个流程都可以根据N的开始和步骤生成自己的流程 - 例如,一个计数组合0, 3, 6...
,处理两个计数组合1, 4, 7...
等等。除非您使用C / Cython,否则这可能会更慢。
解决方案3(或可能解决方案0?)将转到数学堆栈交换并询问是否存在解决此问题的数学解决方案而不是计算解决方案。