python - 赛通 0.2 : prange slowing down code unexpectedly

标签 python multithreading numpy parallel-processing cython

在两种情况下考虑优化的 cython 代码:

    for j in xrange(8):
        for x in xrange(1, 600):
            tmp[j] = 0.0
            for y in xrange(1, 800):
                tmp[j] += mag[j, x - 1, y - 1]
                hgi_out[j, x, y] = tmp[j] + hgi_out[j, x - 1, y]       

和:

    for j in prange(8):  # < prange used for parallelization with openmp
        for x in xrange(1, 600):
            tmp[j] = 0.0
            for y in xrange(1, 800):
                tmp[j] += mag[j, x - 1, y - 1]
                hgi_out[j, x, y] = tmp[j] + hgi_out[j, x - 1, y]       

在这两种情况下,代码都位于声明了 nogil 的 native 函数和具有内存 View 和优化布局的 numpy 数组中。第一种情况的基准测试运行时间为 14.97 毫秒,而第二种情况的 26.64 几乎翻了一番!!

除上述情况外,我还有其他功能,其中 prange 的使用极大地提高了我的多核机器的性能,我不明白发生了什么。

关于为什么 prange 会减慢代码的任何想法?

FWIW,这是完整的原始代码:

# cython: boundscheck=False
# cython: wraparound=False
# cython: nonecheck=False
# cython: overflowcheck.fold=True
# cython: embedsignature=False
# cython: cdivision=True
# cython: cdivision_warnings=False
# cython: always_allow_keywords=False
# cython: profile=False
# cython: linetrace=False
# cython: infer_types=False
# cython: language_level=2
# cython: c_string_type=unicode
# cython: c_string_encoding=utf-8
# cython: type_version_tag=True
# cython: unraisable_tracebacks=True
from __future__ import division
import numpy as np
cimport numpy as np
cimport cython
from cython.parallel import prange

DTYPE = np.int
ctypedef np.int_t DTYPE_t
UITYPE = np.uint
ctypedef np.uint_t UITYPE_t
U8TYPE = np.uint8
ctypedef np.uint8_t U8TYPE_t 
F32TYPE = np.float32
ctypedef np.float32_t F32TYPE_t
F64TYPE = np.float64
ctypedef np.float64_t F64TYPE_t
ctypedef Py_ssize_t DSIZE_t

cdef void native_hog_integral_b(F64TYPE_t [:, :, ::1] mag,
                                F64TYPE_t [:, :, ::1] hgi_out) nogil:
    cdef DSIZE_t m, n, x, y, j, dims = mag.shape[0]
    cdef F64TYPE_t [32] tmp
    cdef F64TYPE_t val = 0
    m, n = mag.shape[1] + 1, mag.shape[2] + 1
    for j in prange(dims):
        for x in xrange(1, m):
            tmp[j] = 0.0
            for y in xrange(1, n):
                tmp[j] += mag[j, x - 1, y - 1]
                hgi_out[j, x, y] = tmp[j] + hgi_out[j, x - 1, y]

def hog_integral_b(mag, hgi_out=None, orientations=8):
    if hgi_out is None:
        hgi_out = np.zeros((orientations + 1, mag.shape[0] + 1, mag.shape[1] + 1), dtype=F64TYPE)
    native_hog_integral_b(mag, hgi_out)
    return hgi_out

要测试上面的代码,尝试:

mg2 = np.random.rand(9, 600, 800).astype(F64TYPE)
hg2 = np.zeros((9, mg2.shape[1] + 1, mg2.shape[2] + 1), dtype=F64TYPE)
print timeit(lambda:hog_integral_b(mg2, hgi_out=hg2), number=10)

更新:

好吧,我仔细查看了我的 setup.py 编译器选项:

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
import numpy as np

ext_modules = [Extension("hog_cy", ["hog_cy.pyx"],
                         #extra_compile_args = ["-O3", "-fopenmp", "-fno-strict-aliasing"],
                         extra_compile_args = ["-O3", "-fopenmp"],
                         extra_link_args=["-fopenmp"]
                        )]

setup (
    name = 'performance test app',
    cmdclass = {'build_ext': build_ext},
    include_dirs = [np.get_include()],
    ext_modules = ext_modules,
)

选项 -fno-strict-aliasing 似乎是问题所在,一旦关闭,我就没有加速但也没有损失。

最佳答案

你正在制作一场 GIL 战斗,因为 prange 不在 nogil block 内。您的代码中没有并发性,只有多个线程竞争 GIL 所有权:

cimport cython
from cython.parallel cimport prange, parallel

cdef void native_hog_integral_b(F64TYPE_t [:, :, ::1] mag, 
                                F64TYPE_t [:, :, ::1] hgi_out):

    cdef DSIZE_t m, n, j, dims = mag.shape[0]
    cdef F64TYPE_t val = 0
    m, n = mag.shape[1] + 1, mag.shape[2] + 1
    with nogil, parallel():
        cdef DSIZE_t x, y
        cdef F64TYPE_t tmp
        for j in prange(dims):
            for x in range(1, m):
                tmp = 0.0
                for y in range(1, n):
                    tmp += mag[j, x - 1, y - 1]
                    hgi_out[j, x, y] = tmp + hgi_out[j, x - 1, y]

关于python - 赛通 0.2 : prange slowing down code unexpectedly,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21333018/

相关文章:

python - 使用带有多个映射函数的 pandas applymap()

python - 未正确调用 DataFrame 构造函数!错误

python - 在 Tkinter 帧上播放带音频的视频

c++ - 管理 C 套接字中客户端突然断开连接的好方法

python - '编程错误 : function avg(character varying) does not exist' - Django project

java - 有ConcurrentHashMap为什么还要synchronizedMap()?

c - Unix数据报套接字正在向自身而不是远程发送消息

python - 生成相同随机数据的简单方法

python - scipy.cluster.vq.kmeans2 中的 "Matrix is not positive definite"错误

python - 将一个数组的每个元素除以另一个数组的每个元素