Numba опережает время компиляции рекурсивной функции - PullRequest
0 голосов
/ 23 ноября 2018

Я пытаюсь скомпилировать рекурсивную функцию раньше времени .Как MCVE, давайте возьмем следующую функцию:

#import numba as nb
from numba.pycc import CC
cc = CC('precompiled')

#@nb.njit
@cc.export('gsum', 'int64(int64)')
def gsum(n):
    if n>1:
        return n+gsum(n-1)
    else:
        return 1

if __name__== '__main__':
##    print(gsum(5))
    cc.compile()

Если я запускаю этот код, я получаю следующую трассировку ошибки:

Traceback (most recent call last):
  File "numba_ahead.py", line 17, in <module>
    cc.compile()
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/numba/compiler_lock.py", line 32, in _acquire_compile_lock
    return func(*args, **kwargs)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/numba/pycc/cc.py", line 212, in compile
    objects, dll_exports = self._compile_object_files(build_dir)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/numba/compiler_lock.py", line 32, in _acquire_compile_lock
    return func(*args, **kwargs)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/numba/pycc/cc.py", line 200, in _compile_object_files
    compiler.write_native_object(temp_obj, wrap=True)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/numba/pycc/compiler.py", line 198, in write_native_object
    library = self._cull_exports()
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/numba/compiler_lock.py", line 32, in _acquire_compile_lock
    return func(*args, **kwargs)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/numba/pycc/compiler.py", line 157, in _cull_exports
    locals={}, library=library)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/numba/compiler.py", line 904, in compile_extra
    return pipeline.compile_extra(func)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/numba/compiler.py", line 367, in compile_extra
    return self._compile_bytecode()
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/numba/compiler.py", line 835, in _compile_bytecode
    return self._compile_core()
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/numba/compiler.py", line 822, in _compile_core
    res = pm.run(self.status)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/numba/compiler_lock.py", line 32, in _acquire_compile_lock
    return func(*args, **kwargs)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/numba/compiler.py", line 253, in run
    raise patched_exception
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/numba/compiler.py", line 244, in run
    stage()
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/numba/compiler.py", line 477, in stage_nopython_frontend
    self.locals)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/numba/compiler.py", line 1005, in type_inference_stage
    infer.build_constraint()
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/numba/typeinfer.py", line 816, in build_constraint
    self.constrain_statement(inst)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/numba/typeinfer.py", line 1016, in constrain_statement
    self.typeof_assign(inst)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/numba/typeinfer.py", line 1079, in typeof_assign
    self.typeof_global(inst, inst.target, value)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/numba/typeinfer.py", line 1177, in typeof_global
    typ = self.resolve_value_type(inst, gvar.value)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/numba/typeinfer.py", line 1100, in resolve_value_type
    raise TypingError(msg, loc=inst.loc)
numba.errors.TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Untyped global name 'gsum': cannot determine Numba type of <class 'function'>

File "numba_ahead.py", line 9:
def gsum(n):
    <source elided>
    if n>1:
        return n+gsum(n-1)
        ^

Так что, очевидно, cc.export не знаеттип функции, которую она компилирует, если эта функция сама вызывает.Есть ли способ решить проблему?Когда я компилирую тот же код как раз вовремя с njit (закомментированные строки), код компилируется просто отлично.

1 Ответ

0 голосов
/ 28 мая 2019

Я обнаружил, что при использовании numba иногда просто меняя способ выполнения определенных циклов и вычислений, можно решить эти проблемы.В вашем случае gsum ниже работает:

#import numba as nb
from numba.pycc import CC
cc = CC('precompiled')

#@nb.njit
@cc.export('gsum', 'int64(int64)')
def gsum(n):
    run=True
    sm=n
    while n:
        n=n-1
        sm+=n
    return sm


def slow_gsum(n):
    run=True
    sm=n
    while n:
        n=n-1
        sm+=n
    return sm

def slow_gsum2(n):
    if n>1:
        return n+slow_gsum2(n-1)
    else:
        return 1


cc.compile()

Вы можете проверить это так:

import precompiled
N=1e2
%time out1=precompiled.gsum(N)
%time out2=slow_gsum(N)
%time out3=slow_gsum2(N)
out1==out2,out1==out3,out1

"""output:
CPU times: user 6 µs, sys: 0 ns, total: 6 µs
Wall time: 11 µs
CPU times: user 12 µs, sys: 1e+03 ns, total: 13 µs
Wall time: 15 µs
CPU times: user 44 µs, sys: 1e+03 ns, total: 45 µs
Wall time: 48.9 µs
(True, True, 5050)
"""

Здесь я установил N=1e2, чтобы мы могли проверить ваше рекурсивное решение (собираетсявыше дает макс-рекурсивную ошибку).Вы действительно можете увидеть ускорение numba, перейдя к более высоким значениям N:

N=1e8
%time out1=precompiled.gsum(N)
%time out2=slow_gsum(N)
out1==out2,out1

"""output:
CPU times: user 7 µs, sys: 1e+03 ns, total: 8 µs
Wall time: 11 µs
CPU times: user 6.14 s, sys: 10.9 ms, total: 6.15 s
Wall time: 6.16 s
(True, 5000000050000000)
"""
...