Numba @jit 装饰器有两种编译模式, Nopython 模式和Object 模式。nopython编译模式的行为本质上是编译修饰后的函数,使其完全运行而不需要Python解释器的参与。这是使用Numba jit装饰器的推荐和最佳实践方法,因为它可以获得最佳性能。@jit(nopython=True) 等效于@njit()。
# -*- coding: utf-8 -*-
from numba import jit
import numpy as np
from time import time
@jit(nopython=True) # Set "nopython" mode for best performance, equivalent to @njit
def go_fast(a): # Function is compiled to machine code when called the first time
trace = 0.0
for i in range(a.shape[0]): # Numba likes loops
trace += np.tanh(a[i, i]) # Numba likes NumPy functions
return a + trace # Numba likes NumPy 广播
N = 100
x = np.arange(N**2).reshape(N, N)
since = time()
r = go_fast(x)
print("time elapsed: ", time() - since)
print(r)
如果在nopython模式下编译失败,Numba可以使用对象模式进行编译。如果没有设置nopython=True,这是@jit装饰器的一种回退模式。在这种模式下,Numba将识别可以编译的循环,并将这些循环编译成在机器代码中运行的函数,它将在Python解释器中运行其余的代码(速度变慢)。为获得最佳性能,请避免使用此模式!
每当Numba将Python代码优化为只在本机类型和变量(非Python对象)上工作的本机代码时,就不再需要Python的全局解释器锁(GIL)。如果您传递了nogil=True,则在输入此类编译函数时,Numba将释放GIL。
使用释放GIL运行的代码可与执行Python或Numba代码的其他线程(同一个编译函数或另一个编译函数)同时运行,允许您利用多核系统。如果函数是在对象模式下编译的,则这是不可能的。
当使用nogil=True时,您必须警惕多线程编程的常见陷阱(一致性、同步、竞争条件等)。
@njit(nogil=True)
def f(x, y):
return x + y
为了避免每次调用Python程序时都要进行编译,可以指示Numba将函数编译的结果写入基于文件的缓存中。这是通过传递cache=True来完成的。
@njit(cache=True)
def f(x, y):
return x + y
为已知具有并行语义的函数中的操作启用自动并行化(和相关优化)。有关支持的操作的列表,请参阅Automatic parallelization with @jit。此功能通过传递parallel=True启用,必须与nopython=True一起使用
@jit(nopython=True, parallel=True)
def f(x, y):
return x + y
from numba import jit
@jit
def f(x, y):
# A somewhat trivial example
return x + y
在此模式下,编译将推迟到第一次函数执行。Numba将在调用时推断参数类型,并基于此信息生成优化代码。Numba还可以根据输入类型编译单独的专门化。例如,使用整数或复数调用上面的f()函数将生成不同的代码路径:
>>>f(1, 2)
3
>>>f(2**31, 2**31 + 1)
4294967297
>>> f(1j, 2)
(2+1j)
你可以告诉numba你期望的函数签名(参数类型和返回值类型):
from numba import jit, int32
@jit(int32(int32, int32)) #输入是两个四字节整数,输出也是四字节整数
def f(x, y):
# A somewhat trivial example
return x + y
int32(int32,int32)是函数的签名。在这种情况下,相应的专门化
将由@jit decorator编译,不允许其他专门化。如果您希望对编译器选
择的类型进行精确控制(例如,使用单精度浮点),这将非常有用(通
常会更快)。但是要注意溢出的风险。
>>>f(2**31, 2**31 + 1)
1 #溢出,高位丢失
如果省略返回类型,例如通过写入(int32,int32)而不是
int32(int32,int32),Numba将尝试为您推断它。函数签名也可以是
字符串,您可以将其中几个作为列表传递。
常用的数据类型有:
uint64,各种长度整数。图像处理中unit8很常用。
uint8[:,:] 表示二维无符号8位整数数组(常用于图像数组)
元素的元组,元素的类型是float32
本文分享自 Python可视化编程机器学习OpenCV 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!