広まってほしいPower Appsの関数 - Concurrent関数

# はじめに
Power Appsをユーザーに展開するうえで、アプリの`もっさり感`は可能な限り避けたいところです。
特に上から順番に評価されていく関数の仕組みを考慮すると、データ操作の読み込みを中心に、一度の関数にかかる処理時間が非常に長くなってしまいます。

ここで作業の処理速度の改善のために役立つ技として、[Concurrent 関数](https://learn.microsoft.com/ja-jp/power-platform/power-fx/reference/function-concurrent)を紹介します。

https://learn.microsoft.com/ja-jp/power-platform/power-fx/reference/function-concurrent

この関数は、複数の数式もとい動作を同時に評価することによって、パフォーマンスを向上させることができます。

# [Concurrent 関数](https://learn.microsoft.com/ja-jp/power-platform/power-fx/reference/function-concurrent)による恩恵

例えば、大規模なデータソースから値を取得するとします。
124,364件の郵便番号データを`SharePoint Lists`と`Dataverse`に格納、
一部Excelにデータを入れた複数のデータソースを評価してみます。

:::note warn
このような大規模なSharePoint Listsの運用を推奨しているわけではありません。
実験目的で使用していることをご理解ください。
:::

画面の`OnVisible`プロパティに関数を設定してみます。

**■ [Concurrent 関数](https://learn.microsoft.com/ja-jp/power-platform/power-fx/reference/function-concurrent)ではないパターン**

```javascript:OnVisible
// 1. 処理開始時間
UpdateContext({startTime: Now()});

// 2. Dataverse 郵便番号データを東京都でフィルターし、行数算出
ClearCollect(colSampleDataData1,郵便番号);
UpdateContext({RowsData1: CountRows(colSampleDataData1)});

// 3. Excel 郵便番号データを千葉県でフィルターし、行数算出
ClearCollect(colSampleDataData2,テーブル1);
UpdateContext({RowsData2: CountRows(colSampleDataData2)});

// 4. SharePoint Lists 郵便番号データを埼玉県でフィルターし、行数算出
ClearCollect(colSampleDataData3,Postcode);
UpdateContext({RowsData3: CountRows(colSampleDataData3)});

// 5. 処理終了時間
UpdateContext({endTime: Now()});

```

こんなアプリで検証してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/f63e0957-13f2-e577-e550-3bd8c3dd07eb.png)

**■ [Concurrent 関数](https://learn.microsoft.com/ja-jp/power-platform/power-fx/reference/function-concurrent)のパターン**

```javascript:OnVisible
// 1. 処理開始時間
UpdateContext({startTime: Now()});

// 2. 前述の(2)(3)(4)を同時実行
Concurrent(
    ClearCollect(
        colSampleDataData1,
        郵便番号
    );
    UpdateContext({RowsData1: CountRows(colSampleDataData1)});
    ,
    ClearCollect(
        colSampleDataData2,
        テーブル1
    );
    UpdateContext({RowsData2: CountRows(colSampleDataData2)});
    ,
    ClearCollect(
        colSampleDataData3,
        Postcode
    );
    UpdateContext({RowsData3: CountRows(colSampleDataData3)});
    
);

// 3. 処理終了時間
UpdateContext({endTime: Now()});
```

## パフォーマンス比較の結果
検証は10回実施しました。

|No|Concurrentではない|**Concurrent**|差分|
|:---:|:---:|:---:|:---:|
|1|776.62037037037|**390.046296296296**|386.574074074074|
|2|616.898148148148|**383.101851851851**|233.796296296297|
|3|628.472222222222|**394.675925925926**|233.796296296296|
|4|1523.14814814814|**376.157407407407**|1146.99074074073|
|5|618.055555555555|**365.74074074074**|252.314814814815|
|6|618.055555555555|**385.416666666666**|232.638888888889|
|7|612.268518518518|**381.944444444444**|230.324074074074|
|8|2275.46296296296|**379.629629629629**|1895.83333333333|
|9|621.527777777777|**376.157407407407**|245.37037037037|
|10|603.009259259259|**375**|228.009259259259|


真ん中が`Concurrent`関数です。
単位は`ミリ秒`の比較になります。


並列で動作させている関係で処理が速い。

:::note info
ネットワークの影響など一概に評価が難しいところですが、
基本的に`Concurrent`のほうが早く済みますね。
:::

## [Concurrent 関数](https://learn.microsoft.com/ja-jp/power-platform/power-fx/reference/function-concurrent)の注意点
[Concurrent 関数](https://learn.microsoft.com/ja-jp/power-platform/power-fx/reference/function-concurrent)は並列で処理を実行します。

1. Aという変数を設定
1. AをもとにBを計算する

といった`依存関係`がある式には向きません。

```javascript:依存関係がある例
// 1. aという数値をもとに
Set( a, 1);
// 2. bを設定
Set( b,
    LookUp(
        データソース,
        ID = a
    ).Value
);
```
こういった順番に評価するものを

```javascript:NGな例
Concurrent(
    Set(
        a,
        1
    ),
    Set(
        b,
        LookUp(
            データソース,
            ID = a
        ).Value
    )
)
```

並列で実行するのはNGです❌

# 同時に実行してかまわない場合は処理速度が向上！
`ClearCollect`のようなデータのキャッシュ以外にも

 - `Power Automate`の呼び出し
 - `Patch`関数によるデータ追加（`Collect`はできなそうでした💦）


下記のようなダミーデータを20件分用意して、ガテン系の平文[Concurrent 関数](https://learn.microsoft.com/ja-jp/power-platform/power-fx/reference/function-concurrent)を実行してみます。

| 氏名            | メールアドレス                  | 社員番号  |
|-----------------|---------------------------------|-----------|
| HSDPQ LWDCD     | hsdpq.lwdcd@demo.com            | 992937    |
| LDMQA JGAFH     | ldmqa.jgafh@test.com            | 360700    |
| IRIYY DGGNG     | iriyy.dggng@demo.com            | 525304    |
| LKAOO HNRSK     | lkaoo.hnrsk@test.com            | 093023    |
| BUSFE BEBPV     | busfe.bebpv@test.com            | 838753    |
| FIDSI OWESW     | fidsi.owesw@test.com            | 752486    |
| GOXEQ QZLSN     | goxeq.qzlsn@example.com         | 480583    |
| QBEBH BRLPM     | qbebh.brlpm@example.com         | 658360    |
| ZOTBL EYPUD     | zotbl.eypud@test.com            | 107800    |
| SYIYA DPCAI     | syiya.dpcai@test.com            | 448814    |
| ZBWAT ZQYVE     | zbwat.zqyve@demo.com            | 910429    |
| PWBLS VQLPB     | pwbls.vqlpb@test.com            | 571967    |
| HDXKI AGAZQ     | hdxki.agazq@example.com         | 467686    |
| DOXHK VYNZW     | doxhk.vynzw@demo.com            | 375203    |
| OINFA PDADY     | oinfa.pdady@test.com            | 522669    |
| JXFAB SWFMA     | jxfab.swfma@demo.com            | 204780    |
| SBNZQ IYSLS     | sbnzq.iysls@test.com            | 380920    |
| SLNHF YOTOK     | slnhf.yotok@test.com            | 810953    |
| IKJDK GQUNR     | ikjdk.gqunr@demo.com            | 993965    |
| BHLFP TGNMF     | bhlfp.tgnmf@demo.com            | 911179    |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/7a79e461-5c58-2194-8197-c7166139c5e2.png)

<details><summary>長い関数</summary>

```plaintext:OnSelect
Concurrent(
    Patch(
        qiitaTest,
        Defaults(qiitaTest),
        {
            Title: "HSDPQ LWDCD",
            mail: "hsdpq.lwdcd@demo.com",
            number: 992937
        }
    ),
    Patch(
        qiitaTest,
        Defaults(qiitaTest),
        {
            Title: "LDMQA JGAFH",
            mail: "ldmqa.jgafh@test.com",
            number: 360700
        }
    ),
    Patch(
        qiitaTest,
        Defaults(qiitaTest),
        {
            Title: "IRIYY DGGNG",
            mail: "iriyy.dggng@demo.com",
            number: 525304
        }
    ),
    Patch(
        qiitaTest,
        Defaults(qiitaTest),
        {
            Title: "LKAOO HNRSK",
            mail: "lkaoo.hnrsk@test.com",
            number: 93023
        }
    ),
    Patch(
        qiitaTest,
        Defaults(qiitaTest),
        {
            Title: "BUSFE BEBPV",
            mail: "busfe.bebpv@test.com",
            number: 838753
        }
    ),
    Patch(
        qiitaTest,
        Defaults(qiitaTest),
        {
            Title: "FIDSI OWESW",
            mail: "fidsi.owesw@test.com",
            number: 752486
        }
    ),
    Patch(
        qiitaTest,
        Defaults(qiitaTest),
        {
            Title: "GOXEQ QZLSN",
            mail: "goxeq.qzlsn@example.com",
            number: 480583
        }
    ),
    Patch(
        qiitaTest,
        Defaults(qiitaTest),
        {
            Title: "QBEBH BRLPM",
            mail: "qbebh.brlpm@example.com",
            number: 658360
        }
    ),
    Patch(
        qiitaTest,
        Defaults(qiitaTest),
        {
            Title: "ZOTBL EYPUD",
            mail: "zotbl.eypud@test.com",
            number: 107800
        }
    ),
    Patch(
        qiitaTest,
        Defaults(qiitaTest),
        {
            Title: "SYIYA DPCAI",
            mail: "syiya.dpcai@test.com",
            number: 448814
        }
    ),
    Patch(
        qiitaTest,
        Defaults(qiitaTest),
        {
            Title: "ZBWAT ZQYVE",
            mail: "zbwat.zqyve@demo.com",
            number: 910429
        }
    ),
    Patch(
        qiitaTest,
        Defaults(qiitaTest),
        {
            Title: "PWBLS VQLPB",
            mail: "pwbls.vqlpb@test.com",
            number: 571967
        }
    ),
    Patch(
        qiitaTest,
        Defaults(qiitaTest),
        {
            Title: "HDXKI AGAZQ",
            mail: "hdxki.agazq@example.com",
            number: 467686
        }
    ),
    Patch(
        qiitaTest,
        Defaults(qiitaTest),
        {
            Title: "DOXHK VYNZW",
            mail: "doxhk.vynzw@demo.com",
            number: 375203
        }
    ),
    Patch(
        qiitaTest,
        Defaults(qiitaTest),
        {
            Title: "OINFA PDADY",
            mail: "oinfa.pdady@test.com",
            number: 522669
        }
    ),
    Patch(
        qiitaTest,
        Defaults(qiitaTest),
        {
            Title: "JXFAB SWFMA",
            mail: "jxfab.swfma@demo.com",
            number: 204780
        }
    ),
    Patch(
        qiitaTest,
        Defaults(qiitaTest),
        {
            Title: "SBNZQ IYSLS",
            mail: "sbnzq.iysls@test.com",
            number: 380920
        }
    ),
    Patch(
        qiitaTest,
        Defaults(qiitaTest),
        {
            Title: "SLNHF YOTOK",
            mail: "slnhf.yotok@test.com",
            number: 810953
        }
    ),
    Patch(
        qiitaTest,
        Defaults(qiitaTest),
        {
            Title: "IKJDK GQUNR",
            mail: "ikjdk.gqunr@demo.com",
            number: 993965
        }
    ),
    Patch(
        qiitaTest,
        Defaults(qiitaTest),
        {
            Title: "BHLFP TGNMF",
            mail: "bhlfp.tgnmf@demo.com",
            number: 911179
        }
    )
)
```

</details>

**CSVインポートと等しいくらいの速さでリストができました（違う、そうじゃない）**

もし、Power Appsが遅くて困るんだよな・・・とお悩みの方は、[Concurrent 関数](https://learn.microsoft.com/ja-jp/power-platform/power-fx/reference/function-concurrent)を使ってみてください！