Python:已知瓶颈的JIT

Jas*_*n S 8 python jit pypy numba

有没有办法使用pypy只是为了编译一个函数而不是我的python程序的其余部分?

我有一个已知的瓶颈,我花了99%的CPU时间(主要包含整数移位和XOR)并在Python中尽可能地优化它.除非绝对必要,否则我不想编写和维护C库.

现在我正在使用Anaconda Python,这是一个普通的python,有很多库.我会使用pypy,除非我不想确保我的所有程序的其余部分都能正常工作.

有没有办法只在一个Python函数上显式运行JIT?


编辑:该函数是GF2(Galois字段)中的模块化乘法步骤

https://bitbucket.org/jason_s/libgf2/src/a71a14a035468e703a7c24349be814419cdba2cb/src/libgf2/gf2.py?at=default

特别:

def _gf2mulmod(x,y,m):
    z = 0
    while x > 0:
        if (x & 1) != 0:
            z ^= y
        y <<= 1
        y2 = y ^ m
        if y2 < y:
            y = y2
        x >>= 1
    return z
Run Code Online (Sandbox Code Playgroud)

它需要为bigints工作,所以我不确定如何重写为Cython兼容.

我刚刚尝试了numba的@autojit,但它失败了,因为它不知道要使用哪些变量类型并假设小整数.我似乎无法弄清楚如何告诉它使用标准的Python bigints.

Traceback (most recent call last):
  File "/Users/jason_s/Documents/python/libgf2/src/libgf2/gf2.py", line 440, in <module>
    dlog43 = GF2DiscreteLog(0x100000000065)
  File "/Users/jason_s/Documents/python/libgf2/src/libgf2/gf2.py", line 295, in __init__
    factors = _calculateFactors(poly)
  File "/Users/jason_s/Documents/python/libgf2/src/libgf2/gf2.py", line 264, in _calculateFactors
    if (e1 << m).value != 1:
  File "/Users/jason_s/Documents/python/libgf2/src/libgf2/gf2.py", line 379, in __lshift__
    return self._wrapraw(_gf2lshiftmod(self.value,k,self.poly))
  File "/Users/jason_s/Documents/python/libgf2/src/libgf2/gf2.py", line 195, in _gf2lshiftmod
    return _gf2mulmod(x,_gf2powmod(2,k,m),m)
  File "/Users/jason_s/Documents/python/libgf2/src/libgf2/gf2.py", line 189, in _gf2powmod
    z = _gf2mulmod(z,x,m)
  File "numbawrapper.pyx", line 193, in numba.numbawrapper._NumbaSpecializingWrapper.__call__ (numba/numbawrapper.c:3764)
OverflowError: value too large to convert to signed int
Run Code Online (Sandbox Code Playgroud)

小智 6

不,你不能在PyPy和另一个Python的其他部分中运行Python程序的一部分 - 它不仅仅是一个JIT,它有一个完全不同的对象和许多其他内部表示.

如果您唯一关心的是不想确保程序的其余部分与PyPy一起使用,请放心:几乎所有纯Python代码都与PyPy一起使用,唯一的例外是CPython实现细节.这些都是模糊的,很难意外地编写依赖于大多数代码的代码,而其他代码(例如文件没有被及时自动关闭)不会破坏大多数程序.试试用PyPy运行整个程序.

如果PyPy存在其他问题,您可能只想将此函数转换为C并使用ctypes或调用它cffi.烦人的部分是用Python挂钩(例如通过扩展模块),这是什么ctypescffi对你来说做.您不需要完整的仲裁精度整数库,只需要一个具有一些非常简单操作的位数组:测试最低有效位,左/右移位,小于和按位异或.每个都只是一个微不足道的循环.如果天真的C实现仍然是瓶颈,你可以对所有这些循环进行矢量化.您也可以优化班次以避免复制任何内容.

  • 根据我原来的帖子:"我正在使用**Anaconda Python**,这是一个普通的python,带有一堆库"(我的重点).我不能依靠支持所有这些包的pypy,即使我可以,我也和不熟悉安装的人一起工作,因此我使用的是Anaconda,因为它使这个过程变得简单. (2认同)

Bas*_*els 6

那么使用Cython呢?您可以将这一个函数转换为cython语法,而不是直接编译为C左右.语法应该足够接近python本身,可能只是添加一些正确类型的声明.