sách gpt4 ai đã đi

openmp - cython openmp 单,屏障

In lại 作者:行者123 更新时间:2023-12-02 03:09:40 31 4
mua khóa gpt4 Nike

我正在尝试在 cython 中使用 openmp。我需要在 cython 中做两件事:

i) 在我的 cython 代码中使用 #pragma omp single{} 作用域。

ii) 使用#pragma omp barrier{}

有人知道如何在 cython 中执行此操作吗?

这里有更多的细节。我有一个 nogil cdef 函数 my_fun(),我在 omp for 循环中调用它:

from cython.parallel cimport prange
cimport openmp

cdef int i

with nogil:
for i in prange(10,schedule='static', num_threads=10):
my_func(i)

hiện hữumy_func里面我需要设置一个barrier等待所有线程 catch ,然后只在其中一个线程中执行一个耗时的操作,并且获得了gil,然后释放屏障,以便所有线程同时恢复。

cdef int my_func(...) nogil:

...

# put a barrier until all threads catch up, e.g. #pragma omp barrier

with gil:
# execute time consuming operation in one thread only, e.g. pragma omp single{}

# remove barrier after the above single thread has finished and continue the operation over all threads in parallel, e.g. #pragma omp barrier

...


1 Câu trả lời

Cython 对 openmp 有一些支持,但如果广泛使用 openmp-pragmas,用 C 编写代码并用 Cython 包装结果代码可能更容易。


作为替代方案,您可以使用 verbatim-C 代码和带有定义的技巧来为 Cython 带来一些功能,但是在定义中使用 pragma 并不直接(_Pragma Đúng C99-solution , MSVC 一如既往地使用 __pragma 做自己的事情),有一些例子作为 Linux/gcc 的概念证明:

cdef extern from *:
"""
#define START_OMP_PARALLEL_PRAGMA() _Pragma("omp parallel") {
#define END_OMP_PRAGMA() }
#define START_OMP_SINGLE_PRAGMA() _Pragma("omp single") {
#define START_OMP_CRITICAL_PRAGMA() _Pragma("omp critical") {
"""
void START_OMP_PARALLEL_PRAGMA() nogil
void END_OMP_PRAGMA() nogil
void START_OMP_SINGLE_PRAGMA() nogil
void START_OMP_CRITICAL_PRAGMA() nogil

我们让 Cython 相信,START_OMP_PARALLEL_PRAGMA() 和 Co. 是 nogil 函数,因此它将它们放入 C 代码中,从而被预处理器接收。

我们必须使用语法

#pragma omp single{
//do_something
}

KHÔNG

#pragma omp single
do_something

因为 Cython 生成 C 代码的方式。

用法可能如下所示(我在这里避免使用 from cython.parallel.parallel 因为它对这个简单的例子来说太神奇了):

%%cython -c=-fopenmp --link-args=-fopenmp
cdef extern from *:# as listed above
...

def test_omp():
cdef int a=0
cdef int b=0
with nogil:
START_OMP_PARALLEL_PRAGMA()
START_OMP_SINGLE_PRAGMA()
a+=1
END_OMP_PRAGMA()
START_OMP_CRITICAL_PRAGMA()
b+=1
END_OMP_PRAGMA() # CRITICAL
END_OMP_PRAGMA() # PARALLEL
print(a,b)

Gọi test_omp 在我的机器上使用 2 个线程打印“1 2”,正如预期的那样(可以使用 openmp.omp_set_num_threads(10) 更改线程数)。

但是,上面的代码仍然很脆弱——Cython 的一些错误检查可能会导致无效代码(Cython 使用 goto 来控制流程,并且不可能跳出 openmp-block)。您的示例中会发生这样的事情:

cimport numpy as np
nhập numpy dưới dạng np
def test_omp2():
cdef np.int_t[:] a=np.zeros(1,dtype=int)

START_OMP_SINGLE_PRAGMA()
a[0]+=1
END_OMP_PRAGMA()

print(a)

由于边界检查,Cython 将产生:

START_OMP_SINGLE_PRAGMA();
...
//check bounds:
if (unlikely(__pyx_t_6 != -1)) {
__Pyx_RaiseBufferIndexError(__pyx_t_6);
__PYX_ERR(0, 30, __pyx_L1_error) // HERE WE GO A GOTO!
}
...
END_OMP_PRAGMA();

在这种特殊情况下,将 boundcheck 设置为 false,即

cimport cython
@cython.boundscheck(False)
def test_omp2():
...

会解决上述示例的问题,但一般情况下可能不会。

再一次:在 C 中使用 openmp(并用 Cython 包装功能)是一种更愉快的体验。


作为旁注:Python 线程(由 GIL 管理的线程)和 openmp 线程是不同的,彼此之间一无所知。上面的示例也可以在不释放 GIL 的情况下正常工作(编译和运行)——openmp-threads 不关心 GIL,但由于不涉及 Python 对象,所以不会出错。因此,我已将 nogil 添加到包装的“函数”中,因此它也可以在 nogil block 中使用。

然而,当代码变得更复杂时,它变得不那么明显,不同 Python 线程之间共享的变量未被访问(所有这些都是因为这些访问可能发生在生成的 C 代码中,而这并不清楚Cython 代码),在使用 openmp 时不释放 gil 可能更明智。

关于openmp - cython openmp 单,屏障,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57965780/

31 4 0
行者123
Hồ sơ cá nhân

Tôi là một lập trình viên xuất sắc, rất giỏi!

Nhận phiếu giảm giá Didi Taxi miễn phí
Mã giảm giá Didi Taxi
Giấy chứng nhận ICP Bắc Kinh số 000000
Hợp tác quảng cáo: 1813099741@qq.com 6ren.com