多进程、多线程、并行的调用方式的不同以及python各种常用且优化较好的并行的处理方法,回头要总结一下,概念模糊很蒙蔽。我们这里介绍一下numba强大并且简单易用的并行功能。
import numpy
from numba import njit
def do_trig(x, y):
z = numpy.empty_like(x)
for i in range(x.shape[0]):
for j in range(x.shape[1]):
z[i, j] = numpy.sin(x[i, j]**2) + numpy.cos(y[i, j])
return z
x = numpy.random.random((1000, 1000))
y = numpy.random.random((1000, 1000))
%timeit do_trig(x, y)
下面我们jit一下
@njit
def do_trig(x, y):
z = numpy.empty_like(x)
for i in range(x.shape[0]):
for j in range(x.shape[1]):
z[i, j] = numpy.sin(x[i, j]**2) + numpy.cos(y[i, j])
return z
very nice,改变编译的方式特别是在这种大量循环的情况下能提升非常多速度呢。
接下来我们使用numba中的并行功能来并行化循环。
import numba
from numba import njit,prange
numba.config.NUMBA_DEFAULT_NUM_THREADS=4
@njit(parallel=True)
def do_trig(x, y):
z = numpy.empty_like(x)
for i in prange(x.shape[0]):
for j in prange(x.shape[1]):
z[i, j] = numpy.sin(x[i, j]**2) + numpy.cos(y[i, j])
return z
%timeit do_trig(x, y)
需要注意的是,numba并行的时候使用的线程数通过numba的环境变量来设置,应该针对不同的任务设置大小,并不是越大越好因为调用多个线程也是存在开销的,另外原来的range循环要用numba特有的prange替换,这样numba才能识别循环并且进行相应的并行化。
我们前面提到的vectorize并行化就更简单了。。。可以把直接把矩阵运算进行并行。。。见下:
@vectorize
def do_trig_vec(x, y):
z = math.sin(x**2) + math.cos(y)
return z
%timeit do_trig_vec(x, y)
@vectorize('float64(float64, float64)', target='parallel')
def do_trig_vec_par(x, y):
z = math.sin(x**2) + math.cos(y)
return z
%timeit do_trig_vec_par(x, y)
numba在vectorize修饰函数的情况下,可以直接对矩阵运算进行并行,牛逼,太方便了哈哈哈哈哈哈哈哈,而且用起来真是太简单了。