并行化 Numpy 向量操作
NumPy 是一个包含多维数组对象以及数组处理例程集合的库。正如您可能知道的那样,它不是并行操作,但是并行执行操作可以为我们提供很大的性能优势。我们将使用numexpr库来并行化 NumPy 操作。
数值表达式
NumExpr 是 NumPy 的快速数值表达式求值器。作用于数组的表达式,例如3*a+4*b (其中 a 和 b 是数组),与在Python中执行时相比,被加速并使用更少的内存。此外,它的多线程功能可以利用所有内核,与 NumPy 相比,可显着提高性能。
根据我们的需要,我们将使用 numexpr 包中的评估函数。
Syntax: numexpr.evaluate(ex, local_dict=None, global_dict=None, out=None, order=’K’, casting=’safe’, **kwargs)
Parameters:
- ex: A string forming an expression involving the operands and operators
- local_dict: A dictionary that replaces the local operands in current frame.
- global_dict: A dictionary that replaces the global operands in current frame.
- out: An existing array where the outcome is going to be stored. Care is required to ensured that the size of this array matches the resultant array size.
- order: Controls the iteration order for operands.
- casting: Controls what kind of data casting may occur when making a copy or buffering.
Returns: Resultant array
示例 1:
在这个例子中,我只使用了评估函数的ex参数来执行 a 和 b 之间的加法。
Python3
import numpy as np
import numexpr as ne
a = np.array([[6, 6], [0, 7]])
b = np.array([[19, 17], [13, 19]])
print(ne.evaluate('a+b'))
Python3
import numpy as np
import numexpr as ne
a = np.array([[6, 6], [0, 7]])
b = np.array([[19, 17], [13, 19]])
print(ne.evaluate('c+d', local_dict={'c': a, 'd': b}))
Python3
import numpy as np
import numexpr as ne
a = np.array([[6, 6], [0, 7]])
def calc():
b = np.array([[19, 17], [13, 19]])
out = np.zeros((2, 2))
ne.evaluate('c+d', local_dict={'c': b},
global_dict={'d': a}, out=out)
print(out)
calc()
Python3
import numpy as np
import numexpr as ne
a = np.arange(1000000)
b = np.arange(1000000)
timeit np.add(np.multiply(2, a), np.multiply(4, b))
timeit ne.evaluate('2*a+4*b')
Python3
import numpy as np
import numexpr as ne
a = np.arange(1000000)
timeit np.sin(a)
timeit ne.evaluate('sin(a)')
Python3
import numpy as np
import numexpr as ne
a = np.random.randint(0, 1000, size=(10000, 10))
timeit np.cos(a)
timeit ne.evaluate('cos(a)')
输出:
[[25. 23.]
[13. 26.]]
示例 2:
在此示例中,我使用local_dict参数和 ex 来从本地范围传递 c 和 d 的操作数。
Python3
import numpy as np
import numexpr as ne
a = np.array([[6, 6], [0, 7]])
b = np.array([[19, 17], [13, 19]])
print(ne.evaluate('c+d', local_dict={'c': a, 'd': b}))
输出:
[[25. 23.]
[13. 26.]]
示例 3:
在此示例中,我使用global_dict参数为 d 传递操作数,而 local_dict 参数在 ex 参数中为 c 传递操作数。
Python3
import numpy as np
import numexpr as ne
a = np.array([[6, 6], [0, 7]])
def calc():
b = np.array([[19, 17], [13, 19]])
out = np.zeros((2, 2))
ne.evaluate('c+d', local_dict={'c': b},
global_dict={'d': a}, out=out)
print(out)
calc()
输出:
[[25. 23.]
[13. 26.]]
比较性能
现在,让我们现在对我们的学习进行测试。在以下示例中,我们将使用 NumPy 和 NumExpr 执行相同的操作,并使用timeit对它们进行计时。
示例 1:
我们将执行一个简单的代数表达式,涉及对两行向量进行加法和乘法运算,每个向量的大小为 1000000。为此,我们使用了 NumPy 包中的加法和乘法函数,并从 NumExpr 中求值来模拟它。
Python3
import numpy as np
import numexpr as ne
a = np.arange(1000000)
b = np.arange(1000000)
timeit np.add(np.multiply(2, a), np.multiply(4, b))
timeit ne.evaluate('2*a+4*b')
输出:
示例 2:
在此示例中,我们将使用 NumPy 库中的sin函数,并使用 NumExpr 的对应函数在 1000000 大小的行向量上评估函数。
Python3
import numpy as np
import numexpr as ne
a = np.arange(1000000)
timeit np.sin(a)
timeit ne.evaluate('sin(a)')
输出:
示例 3:
在这个例子中,我们将使用 NumPy 库中的cos函数,以及在 (10000, 10) 大小的矩阵上使用 NumExpr 的评估函数的对应函数。
Python3
import numpy as np
import numexpr as ne
a = np.random.randint(0, 1000, size=(10000, 10))
timeit np.cos(a)
timeit ne.evaluate('cos(a)')
输出: