IT이야기

OpenMP와 파이썬

cyworld 2021. 10. 5. 21:22
반응형

OpenMP와 파이썬


저는 행렬 덧셈, 곱셈 등과 같은 간단한 작업을 수행하기 위해 공유 메모리 머신(C 및 FORTRAN 모두에서)용 OpenMP를 코딩한 경험이 있습니다. (LAPACK과 어떻게 경쟁하는지 보기 위해) 나는 문서를 볼 필요 없이 간단한 작업을 수행할 만큼 OpenMP를 알고 있습니다.

최근에 프로젝트를 위해 Python으로 전환했으며 절대적인 기본 사항 외에 Python에 대한 경험이 없습니다.

내 질문은 다음과 같습니다.

Python에서 OpenMP를 사용 하는 가장 쉬운 방법 은 무엇입니까 ? 가장 쉬운 것은 프로그래머 측에서 가장 적은 노력을 들이는 것을 의미합니까(시스템 시간이 추가되더라도)?

OpenMP를 사용하는 이유는 직렬 코드가 몇 개의 !$OMP흩어져 있는 작동하는 병렬 코드로 변환될 수 있기 때문 입니다. 대략적인 병렬화 를 달성하는 데 필요한 시간 은 놀랍도록 짧습니다. Python에서 이 기능을 복제할 수 있는 방법이 있습니까?

SO에 대한 탐색에서 다음을 찾을 수 있습니다.

  • C 확장
  • 스택리스 파이썬

더 있나요? 내 질문과 가장 잘 맞는 것은?


GIL로 인해 CPython에서 CPU 집약적 작업에 스레드를 사용할 필요가 없습니다. 당신이 중 하나 (멀티 프로세싱을 필요 ) 또는 사용 C 확장이 계산 예를 들어, NumPy와 기능의 일부 동안 릴리스 GIL .

예를 들어 Cython에서 여러 스레드를 사용하는 C 확장을 쉽게 작성할 수 있습니다 .


사이썬

CythonOpenMP를 지원합니다. Cython에서는 prange(병렬 범위) 연산자를 사용하고 -fopenmpsetup.py에 컴파일러 지시문을 추가 하여 OpenMP를 추가할 수 있습니다 .

prange 스탠자에서 작업할 때 GIL이 비활성화된 블록을 지정하기 위해 사용하여 전역 인터프리터 잠금(GIL)비활성화하기 때문에 실행이 병렬로 수행됩니다 with nogil:.

_cython_np.pyx_를 컴파일하려면 아래와 같이 setup.py 스크립트를 수정해야 합니다. -fopenmpOpenMP를 활성화하고 OpenMP 라이브러리와 연결하기 위해 컴파일하는 동안 인수 로 사용하도록 C 컴파일러에 알리도록 지시합니다 .setup.py

Cython을 사용하면 prange,다양한 스케줄링 접근 방식을 선택할 수 있습니다. 고정, 작업 부하가 사용 가능한 CPU에 걸쳐 고르게 분포되어있다. 그러나 일부 계산 영역은 시간적으로 비싸고 다른 영역은 저렴하기 때문에 Cython에 CPU 전체에서 정적사용하여 작업 청크를 동일하게 예약하도록 요청하면 일부 영역의 결과가 다른 영역보다 빠르게 완료되고 해당 스레드는 그러면 가만히 앉아 있다. 동적안내일정 옵션은 작업 부하의 계산 시간이 가변적일 때 CPU가 더 고르게 분산되도록 런타임에 작업을 더 작은 청크로 동적으로 할당하여 이 문제를 완화하려고 시도합니다. 따라서 코드에 대해 올바른 선택은 워크로드의 특성에 따라 달라집니다.

눔바

Numba의 프리미엄 버전인 NumbaPro는 prangeOpenMP 작업을 위한 병렬화 연산자를 실험적으로 지원 합니다.

피쓰란

Pythran(Python 하위 집합용 Python-C++ 컴파일러)은 Python 2.7만 사용하여 실행되지만 벡터화 가능성과 OpenMP 기반 병렬화 가능성을 활용할 수 있습니다. pragma omp지시문을 사용하여 병렬 섹션을 지정합니다(위에서 설명한 Cython의 OpenMP 지원과 매우 유사). 예:

실용주의

파이파이

JIT Python 컴파일러 PyPy는 다중 처리 모듈(다음 참조)을 지원하고 PyPy-STM이라는 프로젝트를 가지고 있습니다. PyPy-STM는 " 동일한 프로세스에서 여러 개의 독립적인 CPU 사용량이 많은 스레드를 실행할 수 있는 PyPy의 특수 개발 버전 "입니다.

참고 사항: 다중 처리

OpenMP는 다중 코어에 대한 저수준 인터페이스입니다. 당신은보고 할 수 있습니다 는 C. 그것은 컴파일 일단 OpenMP를이 C 원시 객체 (예를 들어, 정수와 수레)와 함께 작동하는 동안에만 경우의 OpenMP를 사용하는 것이 합리적, 파이썬 데이터 구조를 공유하고, 높은 수준의 모듈의 작품 코드를 컴파일 중입니다. 컴파일하지 않는 경우(예: 효율적인 numpy 코드를 사용하고 있고 많은 코어에서 실행하려는 경우) 계속 사용하는 것이 아마도 올바른 접근 방식일 것입니다.multiprocessing.multiprocessingmultiprocessing


내가 아는 한, Python용 OpenMP 패키지는 없습니다(있을 경우 어떻게 될지 모르겠습니다). 스레드를 직접 제어하려면 스레딩 라이브러리 중 하나를 사용해야 합니다. 그러나 다른 사람들이 지적한 것처럼 GIL(Global Interpreter Lock)은 성능을 위해 Python에서 다중 스레딩을 약간... 음, 무의미합니다*. GIL은 한 번에 하나의 스레드만 인터프리터에 액세스할 수 있음을 의미합니다.

대신 NumPy/SciPy를 살펴보는 것이 좋습니다. NumPy를 사용하면 단일 작업으로 배열 및 행렬에서 작업하는 Matlab과 유사한 코드를 작성할 수 있습니다. 병렬 처리 기능도 있습니다( SciPy Wiki 참조) .

검색을 시작할 다른 장소:

* 좋습니다. 무의미한 것은 아니지만 Python 코드 외부에서 시간을 소비하지 않는 한(예를 들어 외부 프로세스를 통해 호출되는 popen경우와 같이) 스레드는 편리함 외에는 아무 것도 사지 않을 것입니다.


GIL을 릴리스하고 OpenMP를 사용하려면 Cython을 살펴보십시오. 몇 가지 일반적인 작업에 대한 간단한 병렬 처리를 제공합니다. Cython 문서 에서 더 많은 것을 읽을 수 있습니다 .


아마도 귀하의 응답은 Cython에 있습니다.

"Cython은 cython.parallel 모듈을 통해 기본 병렬 처리를 지원합니다. 이러한 종류의 병렬 처리를 사용하려면 GIL을 릴리스해야 합니다(GIL 릴리스 참조). 현재 OpenMP를 지원하지만 나중에 더 많은 백엔드가 지원될 수 있습니다." 사이썬 문서


저자는 Python에 OpenMP와 유사한 기능을 제공하는 패키지로 설명하는 pymp 라는 패키지가 있습니다. 나는 그것을 사용해 보았지만 다른 사용 사례로 파일 처리. 그것은 효과가 있었다. 나는 그것이 사용하기 매우 간단하다고 생각합니다. 다음은 GitHub 페이지에서 가져온 샘플입니다.

import pymp
ex_array = pymp.shared.array((100,), dtype='uint8')
with pymp.Parallel(4) as p:
    for index in p.range(0, 100):
        ex_array[index] = 1
        # The parallel print function takes care of asynchronous output.
        p.print('Yay! {} done!'.format(index))

http://archive.euroscipy.org/talk/6857 "NumPy 배열의 병렬 루프에 중점을 둔 Cython의 OpenMP 기능을 소개합니다. 소스 코드 예제는 Python에서 OpenMP를 사용하는 방법을 보여줍니다. OpenMP를 사용한 병렬 알고리즘의 결과는 속도 향상이 무엇인지 보여줍니다. 다른 병렬화 전략과 비교하여 다른 데이터 크기에 대해 달성했습니다."

import numpy
import cython
from cython cimport parallel

@cython.boundscheck(False)
@cython.wraparound(False)
def func(object[double, ndim=2] buf1 not None,
        object[double, ndim=2] buf2 not None,
        object[double, ndim=2] output=None,
        int num_threads=2):
    cdef unsigned int x, y, inner, outer
    if buf1.shape != buf2.shape:
        raise TypeError('Arrays have different shapes: %s, %s' % (buf1.shape,
            buf2.shape))
    if output is None:
        output = numpy.empty_like(buf1)
    outer = buf1.shape[0]
    inner = buf1.shape[1]
    with nogil, cython.boundscheck(False), cython.wraparound(False):
        for x in parallel.prange(outer, schedule='static',
                num_threads=num_threads):
            for y in xrange(inner):
                output[x, y] = ((buf1[x, y] + buf2[x, y]) * 2 +
                    buf1[x, y] * buf2[x, y])
return output

참조URL : https://stackoverflow.com/questions/11368486/openmp-and-python

반응형