使用numba处理容器中的多个常量的最佳方法?

时间:2015-02-20 17:20:46

标签: python enums constants numba

编辑:这个问题已经过时了! numba现在支持Enumnamedtuple开箱即用,它们都为分组常量提供了合理的解决方案。


我正在python中进行一些比特转换,并希望用numba加速它。为此,我有很多常量整数值,我必须以一种可读的方式处理。我想将它们组合成类似于枚举的对象,在一个命名空间内具有所有常量,可以使用attribute-get运算符访问。当然我也想,numba了解那里发生的事情,以便通过jit编译保持高速度。我的第一次也是最天真的尝试就是这样:

class SomeConstantsContainer:
    SOME_NAME = 0x1
    SOME_OTHER_CONSTANT = 0x2
    AND_ANOTHER_CONSTANT = 0x4

不幸的是,当我查看注释时,看起来numba不理解值是常量,并且它总是回退到python对象上的慢对象访问。这就是注释所说的内容:

#   $29.2 = global(SomeConstantsContainer: <class 'constants.SomeConstantContainer'>)  :: pyobject
#   $29.3 = getattr(attr=SOME_VARIABLE, value=$29.2)  :: pyobject

我知道我总是可以回到这样的事情:

from numpy import np
SOME_STUPID_CONSTANT = np.int64(0x1)
ANOTHER_STUPID_CONSTANT = np.int64(0x2)

在这种情况下,jit编译器a)不需要查找容器的属性,并且b)确切知道它必须处理普通整数。这样写是非常难看的。我可以将所有常量明确标记为整数,或让容器执行此操作。尽管如此,为了清晰起见,我真的想将容器中的常量分组,并且jit编译版本理解语法,而不是在每次使用常量时浪费时间进行一些慢速python属性查找。任何更好的想法,如何使第二种方法更像第一种方法,但保持高执行速度?是否有一些enum容器,numba理解,我错过了?

编辑: 使用新的enum容器也无济于事:

@enum.unique
class SomeConstantsContainer(enum.IntEnum):
    SOME_NAME = 0x1
    SOME_OTHER_CONSTANT = 0x2
    AND_ANOTHER_CONSTANT = 0x4

这给出了:

    #   $42.3 = global(SomeConstantsContainer: <enum 'SomeConstantsContainer'>)  :: pyobject
    #   $42.4 = getattr(attr=SOME_OTHER_CONSTANT, value=$42.3)  :: pyobject

1 个答案:

答案 0 :(得分:2)

一种不同的方法,但仍然具有包含变量的优点的方法是在包装函数中使用捕获的变量:

def make_numba_functions():
    SOME_NAME = 0x1
    SOME_OTHER_CONSTANT = 0x2
    AND_ANOTHER_CONSTANT = 0x4

    @jit
    def f1(x,y):
        useful code goes here

    @jit
    def f2(x,y,z):
        some more useful code goes here

    return f1, f2

f1,f2 = make_numba_functions()

显然,您可以将此类与使用类作为命名空间相结合,并解压缩外部函数内的内容。

当我尝试使用一个非常基本的示例并使用inspect_types时,我得到了

$0.1 = freevar(A: 10.0)  :: float64

(其中A只是我的常数)。我怀疑这就是你想要的。我确实试着查看生成的汇编程序(os.environ['NUMBA_DUMP_ASSEMBLY']='1'),但我对汇编程序不够好,无法选择相关行并确认它符合您的要求。但是 - 它使用nopython=True编译,这至少表明它有效地工作。

有点黑客,但有希望的效果非常好!