---
title: kupl::parallel_for
description: "创建parallel for并行循环。相较于kupl_parallel_for接口而言，该接口通过lambda函数特性捕获parallel for回调函数的入参， 避免用户入参封装行为，提高接口易用性。"
url: https://www.hikunpeng.com/document/detail/zh/kunpenghpcs/hpckit/devg/KunpengHPCKit_developer_033.html
sourcePath: /source/zh/kunpenghpcs/hpckit/devg/KunpengHPCKit_developer_033.html
indexId: 51cc3ce036676d9613aaf8a8ba14a923a8df5af58d9ec81118133b062f101cbd67
---
# kupl::parallel_for

创建parallel for并行循环。相较于kupl_parallel_for接口而言，该接口通过lambda函数特性捕获parallel for回调函数的入参， 避免用户入参封装行为，提高接口易用性。

#### 接口定义

kupl::parallel_for(kupl_parallel_for_desc_t *desc, const pf_lambda &func);


类型定义

using pf_lambda = std::function<void(const kupl_nd_range_t *nd_range, const int tid, const int tnum)>;


**表1 参数定义**

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


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

| 参数名 | 类型 | 描述 |
| --- | --- | --- |
| field\_mask | uint64\_t | 结构体中有效字段的掩码，使用kupl\_parallel\_for\_desc\_field中的位标识。此掩码中未指定的字段将被忽略。当前所有字段都为必填项，可以使用KUPL\_PARALLEL\_FOR\_DESC\_FIELD\_DEFAULT表示所有字段都生效。 具体可设置的掩码： KUPL\_PARALLEL\_FOR\_DESC\_FIELD\_RANGE：range生效 KUPL\_PARALLEL\_FOR\_DESC\_FIELD\_EGROUP：egroup生效 KUPL\_PARALLEL\_FOR\_DESC\_FIELD\_CONCURRENCY：concurrency生效 KUPL\_PARALLEL\_FOR\_DESC\_FIELD\_POLICY: policy生效 KUPL\_PARALLEL\_FOR\_DESC\_FIELD\_DEFAULT:上述所有字段都生效 |
| range | kupl\_nd\_range\_t \* | parallel for范围，指向kupl\_nd\_range\_t结构体的指针，具体见下方kupl\_nd\_range\_t数据结构表。 |
| 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_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数据结构说明具体见下表 |


**表5 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


**表6 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 <atomic>
#include <assert.h>
#include "kupl.h"

int main()
{
    int count = 10;
    kupl_nd_range_t range;
    KUPL_1D_RANGE_INIT(range, 0, count);
    kupl_parallel_for_desc_t desc = {
        .field_mask = KUPL_PARALLEL_FOR_DESC_FIELD_DEFAULT,
        .range = &range,
        .egroup = nullptr,
        .concurrency = count,
        .policy = KUPL_LOOP_POLICY_STATIC,
    };

    std::atomic<size_t> sum(0);
    const size_t loop_size = 1000000;
    size_t sum_cal = (1 + loop_size) * loop_size / 2;
    size_t *data = (size_t *)malloc(loop_size * sizeof(loop_size));
    for (size_t i = 0; i < loop_size; i++) {
        data[i] = i + 1;
    }

    int ret = kupl::parallel_for(&desc, [&](const kupl_nd_range_t *nd_range, int tid, int tnum) {
        int start_index = nd_range->nd_range[0].lower * (loop_size / count);
        size_t local_sum = 0;
        for (size_t i = 0; i < loop_size / count; i++) {
            local_sum += data[start_index + i];
        }
        sum += local_sum;
    });
    assert(ret == KUPL_OK);
    assert(sum.load() == sum_cal);
    printf("sum: %lu\n", sum.load());
}
```

运行结果如下。

```
sum: 500000500000
```

上述示例演示了使用kupl::parallel_for并行计算1-1000000的和。首先通过KUPL_1D_RANGE_INIT宏配置了parallel for范围，定义了1维的step步长为1，范围从0到count的for循环描述；其次配置了parallel for任务描述，并发度为count、使用所有执行器，使用静态切分策略；最终通过kupl_parallel_for函数执行for循环。注：以上运行结果以实际为准，上述结果仅供参考。
