---
title: kupl_parallel_for
description: "创建parallel for并行循环。"
url: https://www.hikunpeng.com/document/detail/zh/kunpenghpcs/hpckit/devg/KunpengHPCKit_developer_032.html
sourcePath: /source/zh/kunpenghpcs/hpckit/devg/KunpengHPCKit_developer_032.html
indexId: eb6c1939b87bd8a0a1eb844eaa3e5b6de61c645a34cd41608cdb0b7c1bf0b43b67
---
# kupl_parallel_for

创建parallel for并行循环。

#### 接口定义

int kupl_parallel_for(kupl_parallel_for_desc_t *desc, kupl_pf_func_t func, void *args);


#### 参数


**表1 参数定义**

| 参数名 | 类型 | 描述 | 输入/输出 |
| --- | --- | --- | --- |
| desc | kupl\_parallel\_for\_desc\_t \* | parallel for循环任务的描述，指向kupl\_parallel\_for\_desc\_t结构体的指针，具体见下方kupl\_parallel\_for\_desc\_t数据结构表 | 输入 |
| func | kupl\_pf\_func\_t | parallel for循环任务的函数，该函数必须定义为如下形式：void (\*kupl\_pf\_func\_t)(kupl\_nd\_range\_t \*nd\_range, void \*args, int tid, int tnum)；其中args为该结构体传入的args参数，nd\_range表示经过kupl\_parallel\_for内部处理后该函数实际执行的循环区域，tid与tnum表示当前函数执行所在线程编号与总线程数 | 输入 |
| args | void \* | func函数需要传入的参数 | 输入 |


**表2 kupl_parallel_for_desc_t的数据结构定义**

| 参数名 | 类型 | 描述 |
| --- | --- | --- |
| field\_mask | uint64\_t | 结构体中有效字段的掩码，使用 kupl\_parallel\_for\_desc\_field 中的位标识。此掩码中未指定的字段将被忽略。当前所有字段都为必填项。 |
| range | kupl\_nd\_range\_t \* | parallel for范围，指向kupl\_nd\_range\_t结构体的指针，请参见表3 |
| egroup | kupl\_egroup\_h | 执行for循环任务的egroup，即能在哪个egroup中的executor执行器上执行；可设置为空指针，即不指定egroup |
| concurrency | int | for循环任务的并发度；可设置为 KUPL\_CONCURRENCY\_DEFAULT ，即不指定并发度 |
| policy | kupl\_loop\_policy\_type\_t | parallel for任务遵循的切分策略，当前可设置为KUPL\_LOOP\_POLICY\_STATIC，表示静态切分策略：平均切 KUPL\_LOOP\_POLICY\_DYNAMIC，表示动态切分策略， KUPL\_LOOP\_POLICY\_TASK，表示所有任务会被静态切分但会被以task形式提交用于动态调度 |


**表3 kupl_nd_range_t的数据结构定义**

| 参数名 | 类型 | 描述 |
| --- | --- | --- |
| dim | int | parallel for范围的维度，最大值为KUPL\_MAX\_DIM\_SIZE，当前为3 |
| nd\_range | kupl\_range\_t[] | 每个维度的具体范围，例如nd\_range[0]表示维度0的范围；nd\_range数组大小为KUPL\_MAX\_DIM\_SIZE；kupl\_range\_t数据结构说明具体见下表 |


**表4 kupl_range_t的数据结构定义**

| 参数名 | 类型 | 描述 |
| --- | --- | --- |
| lower | int64\_t | parallel for循环的起始值，即范围的下限 |
| upper | int64\_t | parallel for循环的结束值，即范围的上限 |
| step | int64\_t | parallel for循环的步长，即每次循环增大的值 |
| blocksize | int64\_t | 任务拆分后，每次执行一个block，每个block包含的最小迭代次数是blocksize，可以使用KUPL\_BLOCKSIZE\_DEFAULT表示默认blocksize。当前静态切分策略下blocksize不生效，kupl会按线程数均分数据。只有动态切分和task切分策略下生效，blocksize默认值为1。 |


由于kupl_nd_range_t的数据结构较为复杂，因此在允许用户自行配置数据结构的同时，也提供了相应的宏，以供用户便捷地配置维度为1的kupl_nd_range_t。具体的宏如表 kupl_nd_range_t的宏定义所示。

注：大于一维的任务总数要保证小于int上限，即总blocks < 2^31 - 1


**表5 kupl_nd_range_t的宏定义**

| 宏 | 描述 |
| --- | --- |
| KUPL\_1D\_RANGE\_INIT(\_range, \_col\_begin, \_col\_end) | 配置维度为1、步长为1的parallel for范围 具体功能： 将\_range的维度设置为1； 将(\_range).nd\_range[0]的下限，上限，步长，块大小分别设置为\_col\_begin、\_col\_end、1、KUPL\_BLOCKSIZE\_DEFAULT |
| KUPL\_STRIDE\_1D\_RANGE\_INIT(\_range, \_col\_begin, \_col\_end, \_col\_step, \_col\_blocksize) | 配置维度为1的parallel for范围 具体功能： 将\_range的维度设置为1； 将(\_range).nd\_range[0]的下限，上限，步长，块大小分别设置为\_col\_begin、\_col\_end、\_col\_step、\_col\_blocksize |
| KUPL\_2D\_RANGE\_INIT(\_range, \_row\_begin, \_row\_end, \_col\_begin, \_col\_end) | 配置维度为2、步长为1的parallel for范围 具体功能： 将\_range的维度设置为2；将(\_range).nd\_range[0]的下限、上限、步长、块大小分别设置为\_col\_begin、\_col\_end、1、KUPL\_BLOCKSIZE\_DEFAULT；将(\_range).nd\_range[1]的上限、下限、步长、块大小分别设置为\_row\_begin、\_row\_end、1、KUPL\_BLOCKSIZE\_DEFAULT |
| KUPL\_STRIDE\_2D\_RANGE\_INIT(\_range, \_row\_begin, \_row\_end, \_row\_step, \_row\_blocksize, \_col\_begin, \_col\_end, \_col\_step, \_col\_blocksize) | 配置维度为2的parallel for范围 具体功能： 将\_range的维度设置为2；将(\_range).nd\_range[0]的下限、上限、步长、块大小分别设置为\_col\_begin、\_col\_end、\_col\_step、\_col\_blocksize；将(\_range).nd\_range[1]的上限、下限、步长、块大小分别设置为\_row\_begin、\_row\_end、\_row\_step、\_row\_blocksize |
| KUPL\_3D\_RANGE\_INIT(\_range, \_page\_begin, \_page\_end, \_row\_begin, \_row\_end, \_col\_begin, \_col\_end) | 配置维度为3、步长为1的parallel for范围 具体功能： 将\_range的维度设置为3；将(\_range).nd\_range[0]的下限、上限、步长、块大小分别设置为\_col\_begin、\_col\_end、1、KUPL\_BLOCKSIZE\_DEFAULT；将(\_range).nd\_range[1]的下限、上限、步长、块大小分别设置为\_row\_begin、\_row\_end、1、KUPL\_BLOCKSIZE\_DEFAULT；将(\_range).nd\_range[2]的下限、上限、步长、块大小分别设置为\_page\_begin、\_page\_end、1、KUPL\_BLOCKSIZE\_DEFAULT |
| KUPL\_STRIDE\_3D\_RANGE\_INIT(\_range, \_page\_begin, \_page\_end, \_page\_step, \_page\_blocksize, \_row\_begin, \_row\_end, \_row\_step, \_row\_blocksize, \_col\_begin, \_col\_end, \_col\_step, \_col\_blocksize) | 配置维度为3的parallel for范围 具体功能： 将\_range的维度设置为3；将(\_range).nd\_range[0]的下限、上限、步长、块大小分别设置为\_col\_begin、\_col\_end、\_col\_step、\_col\_blocksize; 将(\_range).nd\_range[1]的下限、上限、步长、块大小分别设置为\_row\_begin、\_row\_end、\_row\_step、\_row\_blocksize; 将(\_range).nd\_range[2]的下限、上限、步长、块大小分别设置为\_page\_begin、\_page\_end、\_page\_step、\_page\_blocksize |


#### 返回值

- 成功：返回KUPL_OK
- 失败：返回KUPL_ERROR


#### 示例

一维示例：

```
#include <stdio.h>
#include <pthread.h>
#include "kupl.h"
static inline void task_in_loop(kupl_nd_range_t *nd_range, void *args, int tid, int tnum)
{
    for (int64_t i = nd_range->nd_range[0].lower; i < nd_range->nd_range[0].upper; i += nd_range->nd_range[0].step) {
        printf("pthread %lu: task_in_loop exe %d job\n", pthread_self(), i);
    }
}
int main()
{
    const int num_threads = kupl_get_num_executors();
    int count = num_threads;
    kupl_nd_range_t range;
    KUPL_1D_RANGE_INIT(range, 0, count);
    int executors[num_threads];
    for (int i = 0; i < num_threads; i++) {
        executors[i] = i;
    }
    kupl_egroup_h eg = kupl_egroup_create(executors, num_threads);
    kupl_parallel_for_desc_t desc = {
        .field_mask = KUPL_PARALLEL_FOR_DESC_FIELD_DEFAULT,
        .range = &range,
        .egroup = eg,
        .concurrency = num_threads,
        .policy = KUPL_LOOP_POLICY_STATIC
    };
    kupl_parallel_for(&desc, task_in_loop, nullptr);
    kupl_egroup_destroy(eg);
}
```

运行结果如下。

```
pthread 281473368858656: task_in_loop exe 0 job
pthread 281473335971872: task_in_loop exe 2 job
pthread 281473344426016: task_in_loop exe 1 job
pthread 281473327517728: task_in_loop exe 3 job
```

三维示例：```
#include <stdio.h>
#include <pthread.h>
#include "kupl.h"
static inline void task_in_loop(kupl_nd_range_t *nd_range, void *args, int tid, int tnum)
{
    for (int64_t i = nd_range->nd_range[0].lower; i < nd_range->nd_range[0].upper; i += nd_range->nd_range[0].step) {
        for (int64_t j = nd_range->nd_range[1].lower; j < nd_range->nd_range[1].upper; j += nd_range->nd_range[1].step) {
            for (int64_t k = nd_range->nd_range[2].lower; k < nd_range->nd_range[2].upper; k += nd_range->nd_range[2].step) {
                printf("pthread %lu: task_in_loop exe [%d : %d : %d] job\n", pthread_self(), i, j, k);
            }
        }
    }
}
int main()
{
    const int num_threads = kupl_get_num_executors();
    int count = num_threads;
    kupl_nd_range_t range;
    KUPL_3D_RANGE_INIT(range, 0, count, 0, count, 0, count);
    int executors[num_threads];
    for (int i = 0; i < num_threads; i++) {
        executors[i] = i;
    }
    kupl_egroup_h eg = kupl_egroup_create(executors, num_threads);
    kupl_parallel_for_desc_t desc = {
        .field_mask = KUPL_PARALLEL_FOR_DESC_FIELD_DEFAULT,
        .range = &range,
        .egroup = eg,
        .concurrency = num_threads,
        .policy = KUPL_LOOP_POLICY_STATIC
    };
    kupl_parallel_for(&desc, task_in_loop, nullptr);
    kupl_egroup_destroy(eg);
}
```


运行结果如下。

```
pthread 281472966852640: task_in_loop exe [0 : 0 : 0] job
pthread 281472966852640: task_in_loop exe [0 : 0 : 1] job
pthread 281472966852640: task_in_loop exe [0 : 1 : 0] job
pthread 281472966852640: task_in_loop exe [0 : 1 : 1] job
pthread 281472950931488: task_in_loop exe [1 : 0 : 0] job
pthread 281472950931488: task_in_loop exe [1 : 0 : 1] job
pthread 281472950931488: task_in_loop exe [1 : 1 : 0] job
pthread 281472950931488: task_in_loop exe [1 : 1 : 1] job
```

上述示例演示了KUPL执行parallel for循环任务的流程。上述示例中，首先通过KUPL_1D_RANGE_INIT宏配置了parallel for范围，定义了1维的step步长为1，范围从0到count的for循环描述；其次配置了parallel for任务描述，任务的函数为task_int_loop，参数为空，并发度为执行器数量、使用所有执行器；最终通过kupl_parallel_for函数执行for循环。注：以上运行结果以实际为准，上述结果仅供参考。
