1. *用numba为python写高性能C扩展
numba是利用llvm加速python的技术,虽然现在还在开发中,但已经基本可用了
numba有代码预热,如果迭代太少反而会减低效率
from numba import jit,int64,int32,float32,float64
1.1. 基本用法:装饰符@jit
1.1.1. 使用装饰符@jit可以延迟编译并进行优化
def f_org(x, y): # A somewhat trivial example return x + y
from numba import jit @jit def f(x, y): # A somewhat trivial example return x + y
f(1,2)
3
f(1j, 2)
(2+1j)
1.1.2. 使用@jit标注类型快速编译
@jit(int32(int32, int32)) def fint(x, y): # A somewhat trivial example return x + y
fint(1,2)
3
def f_org(x, y): # A somewhat trivial example return x + y
0
def f_org(x, y): # A somewhat trivial example return x + y
1
numba必须为用到的所有函数加上@jit
,否则会拖慢运算
def f_org(x, y): # A somewhat trivial example return x + y
2
def f_org(x, y): # A somewhat trivial example return x + y
3
def f_org(x, y): # A somewhat trivial example return x + y
4
我们来看看加速的效果怎么样
def f_org(x, y): # A somewhat trivial example return x + y
5
def f_org(x, y): # A somewhat trivial example return x + y
6
1.2. 使用@generated_jit()编译时控制特殊化选项
虽然jit()装饰器在许多情况下是有用的,有时你想编写一个具有不同实现取决于其输入类型的函数。 generated_jit()装饰器允许用户在编译时控制特殊化的选择,同时充满保留JIT函数的运行时执行速度。
假设你想编写一个函数,该函数根据某些约定返回一个给定值是否是一个"丢失"值。为了举例,让我们采用以下定义:
- 对于浮点参数,缺少的值是NaN
- Numpy datetime64和timedelta64参数,缺少的值是NaT
- 其他类型没有缺少值的概念。
编译时逻辑很容易使用generated_jit()装饰器实现:
def f_org(x, y): # A somewhat trivial example return x + y
7
这里有几点要注意:
- 装饰函数使用参数的Numba类型调用,而不是它们的值。
- 装饰函数实际上不计算结果,它返回一个可调用的实现给定类型的函数的实际定义。
- 可以在编译时预先计算一些数据(上面缺少的变量),以便在编译的实现中重用它们。
- 函数定义使用与修饰函数中的参数相同的名称,这是必需的,以确保通过名称传递参数按预期工作。
1.3. 编译可选项
除了基本用法,@jit()
和@generated_jit()
还可以带上一些参数
- nopython
这个关键字表示编译时不使用python的对象,这是一种不太安全的编译方式,容易报错
def f_org(x, y): # A somewhat trivial example return x + y
8
def f_org(x, y): # A somewhat trivial example return x + y
9
3
- nogil
我们知道python受gil限制,使用这个参数可以突破限制,但用了这个就相当于也用了nopython=True
,但要注意解决线程冲突等问题.
from numba import jit @jit def f(x, y): # A somewhat trivial example return x + y
1
from numba import jit @jit def f(x, y): # A somewhat trivial example return x + y
2
from numba import jit @jit def f(x, y): # A somewhat trivial example return x + y
3
- cache
我们也可以使用缓存来提高运行效率
from numba import jit @jit def f(x, y): # A somewhat trivial example return x + y
4
from numba import jit @jit def f(x, y): # A somewhat trivial example return x + y
5
3
1.4. 使用@jitclass编译python的类
这个装饰器比较新,目前容易出错.但用法应该不会有大变化,class可以静态编译的话还是相当可以
from numba import jit @jit def f(x, y): # A somewhat trivial example return x + y
7
from numba import jit @jit def f(x, y): # A somewhat trivial example return x + y
8
from numba import jit @jit def f(x, y): # A somewhat trivial example return x + y
9
1.4.1. 限制
- 一个jitclass类对象在numba编译函数中被当作一个函数(构造函数)。
- isinstance()只在解释器中工作。但在解释器中操作jitclass实例尚未优化。
- jitclasses目前仅在CPU上可用。
1.5. 使用@vectorize和@guvectorize构建numpy的universal function
vectorize(向量化计算)是指是一种特殊的并行计算的方式,相比于一般程序在同一时间只执行一个操作的方式,它可以在同一时间执行多次操作,通常是对不同的数据执行同样的一个或一批指令,或者说把指令应用于一个数组/向量。 python的numpy包以向量化作为其计算的基本特点.而@vectorize
就是将函数作为向量化工具的装饰器
目前,vectorize
装饰器支持编译后被下面的目标使用:
Target | Description |
---|---|
cpu | Single-threaded CPU |
parallel | Multi-core CPU |
cuda | CUDA GPU |
1.5.1. vectorize()
我们可以这样定义一个操作
f(1,2)
0
但这样就限制了通共性,我们可以这样写提高他的通用性
f(1,2)
1
f(1,2)
2
f(1,2)
3
f(1,2)
4
f(1,2)
5
f(1,2)
6
f(1,2)
7
f(1,2)
8
f(1,2)
9
3
0
3
1
3
2
3
3
3
4
3
5
3
6
3
7
3
8
3
9
1.5.2. guvectorize()
vectorize()
允许你编写一次在一个元素上工作的ufuncs 而guvectorize()
装饰器将这个概念进一步提升一步,允许你编写ufuncs来处理输入为任意数量的元素的数组,并返回不同尺寸的阵列。典型的例子是运行中值或卷积滤波器。与vectorize()
函数相反,guvectorize()
函数不返回它们的结果值:它们将它作为数组参数,它必须由函数填充。这是因为数组实际上是由NumPy的dispa分配的
f(1j, 2)
0
f(1j, 2)
1
f(1j, 2)
2
f(1j, 2)
3
f(1j, 2)
4
还没有评论,来说两句吧...