目前很多移动端的深度学习前向运算框架都用到openmp,如ncnn、paddlelite、mace等。所以这篇来介绍一些OpenMP并行编程。
OpenMP是什么
官方的介绍是:OpenMP(Open Multi-Processing,开放多处理)是一种支持多平台共享存储器多处理器编程的C/C++和Fortran语言的规范和API。说的通俗一些就是:在单机上使用的多线程编程的规范和API。为什么是单机呢,因为比如计算机集群,是非共享内存系统,在非共享内存系统上,MPI(Message Passing Interface)或MapReduce会更合适。
OpenMP API
OpenMP API包括以下三部分:1)编译器伪指令;2)运行时函数;3)环境变量。
- 编译器伪指令
在OpenMP支持的C/C++语言中,OpenMP的使用如下:
#pragma omp 指令[子句[,子句] …] //编译制导指令
{ //左大括号和右大括号必须各占一行
code;
}
下面举个例子:
#include <iostream>
#include "omp.h" //OpenMP头文件
using namespace std;
void main()
{
#pragma omp parallel //OpenMP编写开始
{
cout << "Test" << endl;
}
system("pause");
}
编译制导指令以#pragma omp开头,后面跟具体的功能指令。具体的功能指令使用时可查找:https://www.openmp.org/wp-content/uploads/openmp-examples-4.5.0.pdf
- 运行时函数
除了通过编译器伪指令支持多线程编程,OpenMP还有一些支持显式编程的函数。
-- omp_in_parallel:判断当前是否在并行域中
-- omp_get_thread_num:返回线程号
-- omp_set_num_threads:设置后续并行域中的线程格式
-- omp_get_num_threads:返回当前并行区域中的线程数
-- omp_get_max_threads:获取并行域可用的最大线程数目
-- omp_get_num_procs:返回系统中处理器的个数
-- omp_get_dynamic:判断是否支持动态改变线程数目
--omp_set_dynamic:启用或关闭线程数目的动态改变
-- omp_get_nested:判断系统是否支持并行嵌套
-- omp_set_nested:启用或关闭并行嵌套
-- omp_init_lock:初始化锁
-- omp_set_lock:获得锁
-- omp_unset_lock:释放锁
-- omp_destroyed_lock:销毁锁 - 环境变量
OpenMP环境变量是指一些影响OpenMP运行时行为的配置。OpenMP环境变量的优先级低于函数和伪指令。
-- OMP_SCHEDULE指定了运行时负载均衡类型和每次任务分配的循环次数。
-- OMP_NUM_THREADS指定了执行并行区域时使用的默认线程数量。
-- OMP_DYNAMIC决定了是否允许调整执行并行区域的线程数量,如果设置位ture,则OpenMP运行时可能会调整执行并行区域的线程数量,以优化系统资源的使用。
-- OMP_PROC_BIND决定了是否允许线程迁移到其他的处理器上执行。如果位true,则运行时不会在处理器间迁移线程。
-- OMP_NESTED决定了是否支持嵌套线程,如果位true,则支持。
-- OMP_STACKSIZE指定了每个线程拥有的栈大小,如果出现栈溢出,应该将其改大。
-- OMP_THREAD_LIMIT指定了系统能够创建的OpenMP线程的最大值。