2017-11-14 3 views
2

Cythonのバージョン0.27.3を使用して、同じアルゴリズムのpythonとcythonの両方の実装を含む単純なprimalityテストモジュールの次のソースをコンパイルしています。 threadsパラメータを異なる値に設定すると、GILがリリースされてもパフォーマンスは向上しません。これが並行して実行されないようにする何かがありますか?Cythonのパフォーマンスがprange/parallelで増加しない

cdef void _getprimesは、メモリビュースライスをパラメータとして受け取り、そのスライス内のすべての非プライム値を0に設定する必要があります。

primes.pyx

#cython: boundscheck=False, wraparound=False, nonecheck=False 
cimport cython 
from cpython cimport array 
from cython.parallel cimport parallel, prange 
from libc.math cimport sqrt, ceil 
from libc.stdlib cimport malloc, free 
from libc.stdio cimport printf 
import math 

# ===================== 
# Python implementation 
# ===================== 

def pyisprime(n): 
    """Python implementation""" 
    if n < 2 or n & 1 == 0: 
     if n == 2: 
      return True 
     return False 
    for i in range(2, int(math.sqrt(n)) + 1): 
     if n % i == 0: 
      return False 
    return True 

def pygetprimes(nums): 
    return [num for num in nums if pyisprime(num)] 


# ===================== 
# Cython implementation 
# ===================== 
cdef int _isprime(unsigned long long n) nogil: 
    """Cython implementation of a simple primality check""" 
    cdef unsigned long long upper 
    cdef unsigned long long i = 3 
    cdef int prime = 1 
    if n < 2 or n & 1 == 0: 
     if n == 2: 
      return 1 
     return 0 
    upper = <unsigned long long>ceil(sqrt(<double>n)) 
    while i <= upper: 
     if n % i == 0: 
      prime = 0 
      break 
     i += 1 
    return prime 

def isprime(unsigned long long n): 
    """Wrapper for _isprime""" 
    cdef int result 
    with nogil: 
     result = _isprime(n) 
    return result 

cdef void _getprimes(unsigned long long[:] nums, int threads) nogil: 
    cdef unsigned long num 
    cdef int i = 0 
    with parallel(num_threads=threads): 
     for i in prange(nums.shape[0], schedule="dynamic"): 
      if _isprime(nums[i]) == 0: 
       nums[i] = 0 

def getprimes(nums, int threads = 1): 
    """Wrapper for _getprimes""" 
    cdef unsigned long long num 
    cdef unsigned long long[:] primes = array.array("Q", nums) 

    with nogil: 
     _getprimes(primes, threads) 

    return [num for num in primes if num != 0] 

setup.py

#!/usr/bin/env python3 
from distutils.core import setup 
from Cython.Build import cythonize 

setup(
    name="primes", 
    ext_modules=cythonize('primes.pyx'), 
) 

test.py

#!/usr/bin/env python3 
import functools 
import random 
import time 
import primes 

def timed(func): 
    def wrapped(*args, **kwargs): 
     start = time.time() 
     val = func(*args, **kwargs) 
     end = time.time() 
     print(func.__name__, end - start) 
     return val 
    return functools.wraps(func)(wrapped) 


def main(): 
    nums = [random.randint(0, 0xffffff) for _ in range(500000)] 

    pyfoo = timed(primes.pygetprimes) 
    cyfoo = timed(primes.getprimes) 

    x = pyfoo(nums) 
    y = cyfoo(nums, 1) 
    z = cyfoo(nums, 4) 
    assert x == y == z 

if __name__ == "__main__": 
    main() 

私はを実行します

[[email protected]]: ~/Programming/Cython/build/lib.linux-x86_64-3.6>$ ./test.py 
pygetprimes 5.11554741859436 
getprimes 1.1129701137542725 
getprimes 1.1306445598602295 
+0

cythonのドキュメントを参照してください。こちらをご覧ください:http://cython.readthedocs.io/en/latest/src/userguide/parallelism.html#compiling – chrisb

+0

非常に簡単です!あなたが先に進んで答えにするなら、私はそれを受け入れるでしょう。 – Goodies

答えて

4

あなたがパラレル文のためのOpenMPのためのコンパイラフラグを有効にする必要がありそうです:は、私が1から4までスレッドの数を増やすと高速化のいくつかのタイプを示すが、これはそうではないだろうと予想しました実際に何かをする。

は、私はあなたが実際に何を行うに平行文に対してのOpenMP用のコンパイラフラグを有効にする必要があります信じてここに http://cython.readthedocs.io/en/latest/src/userguide/parallelism.html#compiling

# setup.py 
# ... omitted ... 

ext_modules = [ 
    Extension(
     "hello", 
     ["hello.pyx"], 
     extra_compile_args=['-fopenmp'], 
     extra_link_args=['-fopenmp'], 
    ) 
] 
関連する問題