python multiprocessing调用cython openmp方法需要采用spawn方式

先说结论,在Linux系统,如果python multiprocessing要调用的cython的方法中包含了多线程,比如openmp C code,必须手动设定spawn方式产生多进程。
更多的细节在 https://pythonspeed.com/articles/python-multiprocessing/

Linux环境缺省多进程会采用fork方式复制新进程,fork方式不会拷贝多线程的各个子线程,程序会卡住。

由于自己写的方法mt_foo中调用了多线程openmp, Linux系统下必须采用spawn方式复制新进程。Windows操作系统不支持fork方式,不存在该问题。

python测试文件test_mpmt.py

import testpyxc.myfunc as myfunc
import numpy as np
import multiprocessing as mp

if __name__ == '__main__':
		
  mp.set_start_method("spawn")
	
  my_pool = mp.Pool(2)
  my_rslt = my_pool.map(myfunc.mt_foo, [2,10])

cython文件testpyxc/myfunc.pyx

cimport testpyxc.clib as clib
def mt_foo(int n_thread):
    return clib.avg_reduction(n_thread)

testpyxc/clib.pxd

cdef extern from "mpfoo/mpfoo.h":
    double avg_reduction(int)

C源文件src/mtavg.c调用openmp

#include<stdio.h>
#include <omp.h>

double avg_reduction(int n_thread) {
    int N = 100000000;
    int j = 0;
    double tavg = 0;

    omp_set_num_threads(n_thread);

    #pragma omp parallel for reduction(+:tavg)
    for (j = 0; j < N; ++j) {
        tavg += j;
    }

    tavg = tavg / N;
    return tavg;
    
}

运行中感觉采用了multiprocessing并行后,再同时使用openmp的性能提高已经很有限,估计和具体进程数,线程数以及电脑硬件的配置有关。

另外,如果在C openmp中设定线程数为1时,不论以fork或者spawn创建多进程,程序可以正常运行,不会卡住没响应。符合预期。线程数大于1时,仅能用spawn.

测试环境: Ubuntu 20.04 LTS

posted @ 2022-07-22 18:42  daidau  阅读(451)  评论(0编辑  收藏  举报