【问题标题】:numba doesn't parallelize rangenumba 不并行化范围
【发布时间】:2018-10-19 16:12:30
【问题描述】:

我的代码中有要并行化的循环

from numba import njit, prange
from time import time


@njit
def f1(n):
    s = 0
    for i in range(n):
        for j in range(n):
            for k in range(n):
                s += (i * k < j * j) - (i * k > j * j)
    return s


@njit
def f2(n):
    s = 0
    for i in prange(n):
        for j in prange(n):
            for k in prange(n):
                s += (i * k < j * j) - (i * k > j * j)
    return s


@njit(parallel=True)
def f3(n):
    s = 0
    for i in range(n):
        for j in range(n):
            for k in range(n):
                s += (i * k < j * j) - (i * k > j * j)
    return s


@njit(parallel=True)
def f4(n):
    s = 0
    for i in prange(n):
        for j in prange(n):
            for k in prange(n):
                s += (i * k < j * j) - (i * k > j * j)
    return s


for f in [f1, f2, f3, f4]:
    d = time()
    f(2500)
    print('%.02f' % (time() - d))

我知道时间:

27.44
27.34
26.83
13.05

我检查了处理器的活动,前三个功能处于 100%,而第四个功能大约为 300%。

我不明白为什么指定并行并没有改变任何东西并且需要使用 prange。在the doc 中有一个带范围的例子。

【问题讨论】:

  • 有趣。这对我来说似乎是一个错误。我尝试了jitnjit 的所有组合,无论有没有nogil,我总是在f1f3 上得到11 秒,在f4 上得到大约2.5 秒。但是 afaik parallel=True 仍然是一个实验性功能。也许你应该在numbagithub 上提交错误报告。
  • @Scotty1- 感谢您的帮助,我会等一天再报告。 nogil 一般会影响性能吗?
  • 根据我的经验,它没有,但我没有使用任何并发线程。我只是想让它检查它是否可以并行运行而没有任何冲突。
  • 不要在所有循环上使用 prange(你也不会使用 OpenMP 这样做)。通常,目标是对内部循环进行 SIMD 向量化并在外部循环上并行化以获得最佳性能。 fastmath 关键字也与此类操作相关。这将提供更多代数正确的优化,可能会对数值精度产生影响(通过使用部分和进行求和)

标签: python jit numba


【解决方案1】:

我在 Github 上创建了一个问题,一位贡献者非常准确地回答了 (https://github.com/numba/numba/issues/2960#issuecomment-388767318)。

如果他想在这里转发他的答案,我会接受。

【讨论】:

    【解决方案2】:

    来自 Numba 文档:

    @jit 的实验性 parallel=True 选项将尝试优化数组操作并并行运行它们。它还添加了对 prange() 的支持,以显式并行化循环。

    现在,由于您不在函数中执行任何数组操作,因此如果不使用 prange 显式标记循环,Numba 就无法并行化。

    所以只是为了确保没有混淆。 当您在装饰中设置 parallel=True 时,Numba 只会将您的循环拆分为线程,并通过更改显式标记循环;范围 -> 范围。

    在您的 f4() 中,您已将 prange 放在所有 for 循环上,我建议只将 prange 放在最外层循环上,因为您不想冒险从线程中产生线程。 即:

    @njit(parallel=True)
    def f5(n):
        s = 0
        for i in prange(n):
            for j in range(n):
                for k in range(n):
                    s += (i * k < j * j) - (i * k > j * j)
        return s
    

    【讨论】:

    • s不被认为是0维数组吗?如果我将它初始化为 numpy ndarray,它会改变吗?您确定嵌套 prange 吗?我认为它的工作方式与 OMP 不同(例如)。你的意思是进程而不是线程?
    猜你喜欢
    • 2019-11-09
    • 1970-01-01
    • 2021-12-18
    • 1970-01-01
    • 2018-01-18
    • 2021-08-15
    • 1970-01-01
    • 1970-01-01
    • 2018-04-06
    相关资源
    最近更新 更多