Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python numba-guvectorize几乎没有jit快_Python_Performance_Numpy_Parallel Processing_Numba - Fatal编程技术网

Python numba-guvectorize几乎没有jit快

Python numba-guvectorize几乎没有jit快,python,performance,numpy,parallel-processing,numba,Python,Performance,Numpy,Parallel Processing,Numba,我试图并行化一个在许多独立数据集上运行的蒙特卡罗模拟。我发现numba的并行guvectorize实现仅比numba jit实现快30-40% 我在Stackoverflow上发现了这些(,)类似的主题,但它们并没有真正回答我的问题。在第一种情况下,由于回退到对象模式,实现速度减慢,在第二种情况下,原始海报没有正确使用guvectorize-这些问题都不适用于我的代码 为了确保我的代码没有问题,我创建了一段非常简单的代码来比较jit和guvectorize: import timeit impo

我试图并行化一个在许多独立数据集上运行的蒙特卡罗模拟。我发现numba的并行guvectorize实现仅比numba jit实现快30-40%

我在Stackoverflow上发现了这些(,)类似的主题,但它们并没有真正回答我的问题。在第一种情况下,由于回退到对象模式,实现速度减慢,在第二种情况下,原始海报没有正确使用guvectorize-这些问题都不适用于我的代码

为了确保我的代码没有问题,我创建了一段非常简单的代码来比较jit和guvectorize:

import timeit
import numpy as np
from numba import jit, guvectorize

#both functions take an (m x n) array as input, compute the row sum, and return the row sums in a (m x 1) array

@guvectorize(["void(float64[:], float64[:])"], "(n) -> ()", target="parallel", nopython=True)
def row_sum_gu(input, output) :
    output[0] = np.sum(input)

@jit(nopython=True)
def row_sum_jit(input_array, output_array) :
    m, n = input_array.shape
    for i in range(m) :
        output_array[i] = np.sum(input_array[i,:])

rows = int(64) #broadcasting (= supposed parallellization) dimension for guvectorize
columns = int(1e6)
input_array = np.ones((rows, columns))
output_array = np.zeros((rows))
output_array2 = np.zeros((rows))

#the first run includes the compile time
row_sum_jit(input_array, output_array)
row_sum_gu(input_array, output_array2)

#run each function 100 times and record the time
print("jit time:", timeit.timeit("row_sum_jit(input_array, output_array)", "from __main__ import row_sum_jit, input_array, output_array", number=100))
print("guvectorize time:", timeit.timeit("row_sum_gu(input_array, output_array2)", "from __main__ import row_sum_gu, input_array, output_array2", number=100))
这给了我以下输出(时间确实有点不同):

因此,即使并行代码使用所有CPU核心,jit代码仅使用一个(使用htop验证),并行代码的速度也仅为CPU核心数的整数倍,否则性能优势会减弱

我在一台拥有4x AMD Opteron 6380 CPU(总共64个内核)、256GB内存和Red Hat 4.4.7-1操作系统的机器上运行此功能。 我将Anaconda4.2.0与Python3.5.2和Numba0.26.0结合使用

如何进一步提高并行性能,或者我做错了什么


谢谢你的回答。

那是因为
np.sum
太简单了。使用sum处理数组不仅受到CPU的限制,还受到“内存访问”时间的限制。因此,向它扔更多的内核并没有多大区别(当然,这取决于相对于CPU的内存访问速度)

仅针对可视化
np.sum
是这样的(忽略
数据
以外的任何参数):

因此,如果大部分时间都花在访问内存上,那么如果将其并行化,就不会看到任何真正的加速。但是,如果CPU受限的任务是瓶颈,那么使用更多内核将显著加快代码的速度

例如,如果包含一些比加法更慢的操作,您将看到更大的改进:

from math import sqrt
from numba import njit, jit, guvectorize
import timeit
import numpy as np

@njit
def square_sum(arr):
    a = 0.
    for i in range(arr.size):
        a = sqrt(a**2 + arr[i]**2)  # sqrt and square are cpu-intensive!
    return a

@guvectorize(["void(float64[:], float64[:])"], "(n) -> ()", target="parallel", nopython=True)
def row_sum_gu(input, output) :
    output[0] = square_sum(input)

@jit(nopython=True)
def row_sum_jit(input_array, output_array) :
    m, n = input_array.shape
    for i in range(m) :
        output_array[i] = square_sum(input_array[i,:])
    return output_array
我在这里使用了,但应该是等效的:

rows = int(64)
columns = int(1e6)

input_array = np.random.random((rows, columns))
output_array = np.zeros((rows))

# Warmup an check that they are equal 
np.testing.assert_equal(row_sum_jit(input_array, output_array), row_sum_gu(input_array, output_array2))
%timeit row_sum_jit(input_array, output_array.copy())  # 10 loops, best of 3: 130 ms per loop
%timeit row_sum_gu(input_array, output_array.copy())   # 10 loops, best of 3: 35.7 ms per loop
我只使用了4个内核,所以这非常接近可能的加速极限


请记住,如果作业受CPU限制,并行计算只能显著加快计算速度。作为参考,我在2012年Macbook Air 1.6 GHz上的计算时间为12秒和3.8秒。因此,尽管你的机器“更好”,但你的JIT时间和我的一样,而且你的矢量化时间更差。你可能还想使用一些随机数据检查你的两个函数。它们不会产生相同的结果。@JoshAdel我使用以下测试:
input\u array=np.random.rand(行、列)
np.array\u equal(output\u array,output\u array2)
返回True@JohnZwinck我在不同的机器上运行代码,速度越来越慢,速度越慢的机器上guvectorize的加速比越大,所以我怀疑MSeifert下面的评论是正确的。@DriesVanLaethem你是对的。不确定我最初在测试中做了什么,但现在他们同意了。我的道歉OP的“4x AMD Opteron 6380”机器的性能并不比我的2012 Macbook Air好多少,它肯定有一个更差的内存子系统(对吧?)。我测试的机器有一个超级微型H8QG6-F主板,带有16 x 16GB DDR3-1600注册RAM。不知道此设置是比Macbook Air的内存子系统慢还是快。@MSeifert感谢您的清晰详细的解释。我正在重新构造数据集和代码,以限制访问内存的次数。
from math import sqrt
from numba import njit, jit, guvectorize
import timeit
import numpy as np

@njit
def square_sum(arr):
    a = 0.
    for i in range(arr.size):
        a = sqrt(a**2 + arr[i]**2)  # sqrt and square are cpu-intensive!
    return a

@guvectorize(["void(float64[:], float64[:])"], "(n) -> ()", target="parallel", nopython=True)
def row_sum_gu(input, output) :
    output[0] = square_sum(input)

@jit(nopython=True)
def row_sum_jit(input_array, output_array) :
    m, n = input_array.shape
    for i in range(m) :
        output_array[i] = square_sum(input_array[i,:])
    return output_array
rows = int(64)
columns = int(1e6)

input_array = np.random.random((rows, columns))
output_array = np.zeros((rows))

# Warmup an check that they are equal 
np.testing.assert_equal(row_sum_jit(input_array, output_array), row_sum_gu(input_array, output_array2))
%timeit row_sum_jit(input_array, output_array.copy())  # 10 loops, best of 3: 130 ms per loop
%timeit row_sum_gu(input_array, output_array.copy())   # 10 loops, best of 3: 35.7 ms per loop