我有一个非常大的 python 程序,需要几个小时才能完成,在一个核心上运行。
有什么方法可以将其分配给我电脑上的所有 8 个 i7 核心吗?
唯一的问题是任务依赖于之前的计算,例如,这是我的代码的(非常)简化版本:
def code(nums):
num = 1
for loop in range(nums):
num += num * loop
return num
然后运行 code()
counted = code(100000)
我可以在任务管理器上观察 CPU 的使用量(大约 12%),显示它只使用一个核心
有没有办法让这段代码在多个内核上运行?
注意:我遇到的主要困难是它依赖于之前的结果,因此我无法将代码分成多个部分。
编辑:
我在 Windows 10 上使用 Python3
编辑2:
如果可能的话,如果上面的代码是我的完整代码,您能写出解决方案吗?
最佳答案
Python 中的多处理
CPython 是 Python 解释器最常见的实现,如果不使用 python 的 multiprocessing
模块,则不具备对多处理的 native 支持。这是由于Python内存不是线程安全的,引入了全局解释器锁(GIL),因此即使是threading
模块也没有真正实现并行代码。另一方面,multiprocessing
模块启动 Python 解释器的全新实例,并且由于它们不再共享 GIL,因此可以真正跨多个内核并行运行。
因此,如果您希望运行利用多核的 Python 程序,您必须将程序手动分解为子进程,每个子进程都可以在解释器的单独实例上运行。但请务必小心,因为以这种方式利用多个核心的 yield 可能会比跨核心运行所获得的开销更高,但这非常依赖于项目,因此您应该自己检查一下。
来源:
Multicore Python: A tough, worthy, and reachable goal
Multi-Core and Distributed Programming in Python
Multiprocessing vs Threading Python
您的问题的可能解决方案
现在请耐心等待,因为有几个数学步骤,但我确实相信有一种方法可以使您的代码并行化。
首先获取不同 nums
值的输出示例,看看代码的输出是什么:
nums | 1 | 2 | 3 | 4 | 5 | 6 |
-----------------------------------
out | 1 | 2 | 6 | 24 | 120 | 720 |
现在,由于您的代码已设置,您可以看到 code(nums) = code(nums - 1) + code(nums - 1) * (nums- 1)
,所以如果我们可以找到一种从 code(nums - 1)
到 code(nums)
的方法,而实际上不需要知道 code(nums - 1)< 的值
然后我们可以并行化代码。
如果我们现在考虑上表中从 code(nums - 1)
到 code(nums)
的差异,我们会得到下表的差异:
nums | 1 | 2 | 3 | 4 | 5 | 6 |
-----------------------------------
diff | | 1 | 4 | 18 | 96 | 600 |
现在这些差异可能看起来没有形成一种模式,但实际上有一点逻辑上的飞跃,您可以看到 code(nums)
和 code(nums - 1)
是 (nums - 1) * (nums - 1)!
(其中 !
是数学阶乘函数)。因此我们看到您的 code
方法可以等效地写为:
from math import factorial
def code(nums):
num = 1
for i in range(1, nums):
num += i * factorial(i)
return num
现在我们可以并行化您的代码了。我们将使用带有 8 个进程池的 multiprocessing
模块(以匹配您的 8 个核心),并将所需工作的一部分映射到每个核心上,允许它们计算所需的值,然后计算总计将结果加起来,然后简单地将结果加 1 以计算 num
的初始值。
from math import factorial
from multiprocessing import Pool, freeze_support
NUM_CORES = 8
def foo(lower, upper):
sum = 0
for i in range(lower, upper):
sum += i * factorial(i)
return sum
def code(nums):
# Build the list of arguments for the workers so that each gets 1/NUM_CORES of the work.
a, b = divmod(nums, NUM_CORES)
arguments = [(1,a)]
for c in range(2, NUM_CORES):
arguments.append(((c-1)*a, c*a))
arguments.append(((NUM_CORES - 1)*a, NUM_CORES*a + b))
print(arguments)
with Pool(processes=8) as pool:
results = pool.starmap(foo, arguments)
print(1 + sum(results))
if __name__ == '__main__':
freeze_support()
code(100)
需要在底部的 __main__
block 中调用 freeze_support
,以便在 code
方法中正确执行多处理。
关于python - 是否可以在多个核上运行依赖于前一个任务的程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45976342/