gpt4 book ai didi

multithreading - Prange减慢Cython循环

转载 作者:行者123 更新时间:2023-12-03 12:59:24 25 4
gpt4 key购买 nike

考虑两种使用cython prange和openmp来计算随机数的方法,一种是一对一线程,一种是多线程:

def rnd_test(long size1):
cdef long i
for i in range(size1):
rand()
return 1


def rnd_test_par(long size1):
cdef long i
with nogil, parallel():
for i in prange(size1, schedule='static'):
rand()
return 1

首先使用以下setup.py编译函数rnd_test
from distutils.core import setup
from Cython.Build import cythonize

setup(
name = 'Hello world app',
ext_modules = cythonize("cython_test.pyx"),
)

rnd_test(100_000_000)在0.7秒内运行。

然后,使用以下setup.py编译rnd_test_par
from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize

ext_modules = [
Extension(
"cython_test_openmp",
["cython_test_openmp.pyx"],
extra_compile_args=["-O3", '-fopenmp'],
extra_link_args=['-fopenmp'],
)

]

setup(
name='hello-parallel-world',
ext_modules=cythonize(ext_modules),
)

rnd_test_par(100_000_000)只需10秒即可运行!!!

在ipython中使用cython可获得类似的结果:
%%cython
import cython
from cython.parallel cimport parallel, prange
from libc.stdlib cimport rand

def rnd_test(long size1):
cdef long i
for i in range(size1):
rand()
return 1

%%timeit
rnd_test(100_000_000)

1个循环,每个循环最好3:1.5 s


%%cython --compile-args=-fopenmp --link-args=-fopenmp --force
import cython
from cython.parallel cimport parallel, prange
from libc.stdlib cimport rand

def rnd_test_par(long size1):
cdef long i
with nogil, parallel():
for i in prange(size1, schedule='static'):
rand()
return 1

%%timeit
rnd_test_par(100_000_000)

1个循环,每个循环最好3:8.42 s

我究竟做错了什么?我对cython完全陌生,这是我第二次使用它。上次我有很好的经验,所以我决定将其用于蒙特卡洛模拟项目(因此使用rand)。

这是预期的吗?阅读了所有文档后,我认为prange在类似这样的令人尴尬的并行案例中应该能很好地工作。我不明白为什么这无法加快循环速度甚至使循环变得如此慢。

一些其他信息:
  • 我正在运行python 3.6,cython 0.26。
  • gcc版本是“gcc(Ubuntu 5.4.0-6ubuntu1〜16.04.4)5.4.0 20160609”
  • CPU使用率确认并行版本实际上使用了许多内核
    (90%比连续案例的25%)

  • 感谢您提供的任何帮助。我先用numba尝试过,它确实加快了计算速度,但是它还有其他一些问题让我想避免它。我希望Cython在这种情况下可以工作。

    谢谢!!!

    最佳答案

    有了DavidW的有用反馈和链接,我有了一个用于随机数生成的多线程解决方案。
    但是,与单线程(矢量化)的Numpy解决方案相比,节省的时间并不是那么多。 numpy方法在1.2s内生成1亿个数字(内存为5GB),而多线程方法为0.7s。考虑到增加的复杂性(例如使用c++库),我想知道是否值得。也许我将使随机数生成保持单线程状态,并致力于并行化此步骤之后的计算。
    但是,该练习对于理解randon数生成器的问题非常有用。最终,我希望拥有一个可以在分布式环境中工作的框架,并且现在我可以看到,由于生成器本质上具有不可忽略的状态,因此对于随机数生成器而言,挑战甚至会更大。

    %%cython --compile-args=-fopenmp --link-args=-fopenmp --force
    # distutils: language = c++
    # distutils: extra_compile_args = -std=c++11
    import cython
    cimport numpy as np
    import numpy as np
    from cython.parallel cimport parallel, prange, threadid
    cimport openmp

    cdef extern from "<random>" namespace "std" nogil:
    cdef cppclass mt19937:
    mt19937() # we need to define this constructor to stack allocate classes in Cython
    mt19937(unsigned int seed) # not worrying about matching the exact int type for seed

    cdef cppclass uniform_real_distribution[T]:
    uniform_real_distribution()
    uniform_real_distribution(T a, T b)
    T operator()(mt19937 gen) # ignore the possibility of using other classes for "gen"

    @cython.boundscheck(False)
    @cython.wraparound(False)
    def test_rnd_par(long size):
    cdef:
    mt19937 gen
    uniform_real_distribution[double] dist = uniform_real_distribution[double](0.0,1.0)
    narr = np.empty(size, dtype=np.dtype("double"))
    double [:] narr_view = narr
    long i

    with nogil, parallel():
    gen = mt19937(openmp.omp_get_thread_num())
    for i in prange(size, schedule='static'):
    narr_view[i] = dist(gen)
    return narr

    关于multithreading - Prange减慢Cython循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46257321/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com