是否可以在多个内核上运行依赖于先前任务的程序?

时间:2017-08-31 08:05:10

标签: python python-3.x multiprocessing

我有一个非常大的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:

如果可能的话,如果上面的代码是我的完整代码,请编写解决方案吗?

2 个答案:

答案 0 :(得分:2)

Python中的多处理

CPython是Python解释器的最常见实现,在没有使用python的multiprocessing模块的情况下,它没有多处理的本机支持。这是由于全局解释器锁(GIL)引入,因为python内存不是线程安全的,因此即使threading模块也没有真正实现并行代码。另一方面,multiprocessing模块启动Python解释器的全新实例,因为它们不再共享GIL,可以真正并行地跨多个核心运行。

因此,如果您希望运行利用多个核心的python程序,必须手动将程序分解为子流程,每个子流程可以在解释器的单独实例上运行。但要小心,因为以这种方式利用多个内核的收益可能比通过内核运行所获得的成本更高,但这与项目有关,所以你应该自己检查一下。

来源:

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

现在我们可以将代码与您的代码并行化。我们将multiprocessing模块与8个进程池(以匹配您的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)

需要在底部freeze_support块中进行__main__调用,以便在code方法中正确执行多重处理。

答案 1 :(得分:1)

首先,拿一支笔和一张纸,记下你脑海中的计算进度。有没有可以平行的步骤?

如果没有,就不可能使用多核。

如果是,请仔细检查您需要并行执行哪些步骤,所有步骤是否可以并行取决于相同的步骤?或者他们依赖于不同的步骤?

如果是的话......如果不是......

总之,在您可以并行计算之前,首先需要为计算建立拓扑图,以便找到可以,需要什么以及如何进行计算的地方。