其他分享
首页 > 其他分享> > 为什么依存的numba jitt’ed函数的顺序很重要?

为什么依存的numba jitt’ed函数的顺序很重要?

作者:互联网

python中,您可以定义多个可以任意顺序调用的函数,并且在运行时将调用这些函数.一旦存在,这些功能在脚本中定义的顺序就无关紧要.例如,以下内容有效并且可以使用

import numpy as np

def func1(arr):
    out = np.empty_like(arr)
    for i in range(arr.shape[0]):
        out[i] = func2(arr[i])  # calling func2 here which is defined below
    return out

def func2(a):
    out = a + 1
    return out

即使func2是在func1之后定义的,func1也可以调用func2.

但是,如果我用numba装饰这些功能,则会收到错误消息

import numpy as np
import numba as nb


@nb.jit("f8[:](f8[:])", nopython=True)
def func1(arr):
    out = np.empty_like(arr)
    for i in range(arr.shape[0]):
        out[i] = func2(arr[i])
    return out

@nb.jit("f8(f8)", nopython=True)
def func2(a):
    out = a + 1
    return out

>>> TypingError: Failed in nopython mode pipeline (step: nopython frontend)
    Untyped global name 'func2': cannot determine Numba type of <class 
    'numba.ir.UndefinedType'>

因此,numba在使用JIT编译func1时并不知道func2是什么.不过,只需切换这些功能的顺序即可,因此func2在func1之前

@nb.jit("f8(f8)", nopython=True)
def func2(a):
    out = a + 1
    return out

@nb.jit("f8[:](f8[:])", nopython=True)
def func1(arr):
    out = np.empty_like(arr)
    for i in range(arr.shape[0]):
        out[i] = func2(arr[i])
    return out

为什么是这样?我有一种纯粹的python模式可以使用的感觉,因为python是动态类型化的,而不是编译的,而numba根据定义使用JIT确实可以编译函数(因此可能需要对每个函数中发生的一切都有全面的了解?).但是我不明白,如果numba遇到未见过的功能,为什么它不在所有功能范围内搜索.

解决方法:

简短版本-删除“ f8 [:](f8 [:])”

你的直觉是对的.在调用时会检查Python函数,这就是为什么可以不按顺序定义它们的原因.用dis(反汇编)模块查看python字节码可以使这一点变得很清楚-每次调用函数a时,名称b都会被查询为全局变量.

def a():
    return b()

def b():
    return 2

import dis
dis.dis(a)
#  2           0 LOAD_GLOBAL              0 (b)
#              2 CALL_FUNCTION            0
#              4 RETURN_VALUE

在nopython模式下,numba需要静态知道正在调用的每个函数的地址-这样可以使代码更快(不再执行运行时查找),并且还为其他优化(如内联)打开了大门.

也就是说,numba可以处理此案.通过指定类型签名(“ f8 [:](f8 [:])”),您将强制提前编译.忽略它,一个数字将延迟到第一个调用它的函数,它将起作用.

标签:jit,numba,python
来源: https://codeday.me/bug/20191108/2005993.html