【UiPath】コード化されたワークフローで RPA Challenge を動かす その３ - 爆速化編

# はじめに
[前回](https://qiita.com/MasahiroHarada1105/items/fa4bf9e96339d0054a5c)、[前々回](https://qiita.com/MasahiroHarada1105/items/59495e4bb0971841651e)の記事でコード化されたワークフローで RPA Challenage の自動化処理を実装することができました。

しかし、RPA Challenge と言えば爆速化です。RPA Challenge に挑むものとして爆速化は避けて通れない道です。

https://www.uipath.com/ja/community-blog/tutorials/accelerate-processing

というわけで今回は、コード化されたワークフローでどこまで爆速化できるか試してみたいと思います。

この記事は、[UiPath (produced with UiPath Friends) Advent Calendar 2023](https://qiita.com/advent-calendar/2023/uipath) の 15日目です。

https://qiita.com/advent-calendar/2023/uipath

# リファクタリングしてみる
いきなりですが、こちらが修正後のコードになります。
```csharp:RPAChallenge.cs
using System;
using System.Collections.Generic;
using System.Data;
using System.Threading.Tasks;
using UiPath.CodedWorkflows;
using UiPath.Core;
using UiPath.Core.Activities.Storage;
using UiPath.Orchestrator.Client.Models;
using UiPath.Testing;
using UiPath.Testing.Activities.TestData;
using UiPath.Testing.Activities.TestDataQueues.Enums;
using UiPath.Testing.Enums;
using UiPath.UIAutomationNext.API.Contracts;
using UiPath.UIAutomationNext.API.Models;
using UiPath.UIAutomationNext.Enums;
using CodedWorkflow_RPAChallenge.ObjectRepository;

namespace CodedWorkflow_RPAChallenge
{
    public class RPAChallenge : CodedWorkflow
    {
        public TargetAppOptions targetAppOptions => new TargetAppOptions() {
            InteractionMode = NInteractionMode.Simulate,
            OpenMode = NAppOpenMode.IfNotOpen,
            AttachMode = NAppAttachMode.SingleWindow
        };

        // TypeInto のプロパティ (DelayBefore と DelayAfter を 0秒にする)
        public TypeIntoOptions typeIntoOptions => new TypeIntoOptions() {
            DelayBefore = 0,
            DelayAfter = 0
        };

        // Click のプロパティ (DelayBefore と DelayAfter を 0秒にする)
        public ClickOptions clickOptions => new ClickOptions() {
            DelayBefore = 0,
            DelayAfter = 0
        };

        [Workflow]
        public void Execute()
        {
            UiTargetApp screen = uiAutomation.Open(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge, targetAppOptions);

            // 開始ボタンのクリック前に移動
            IDictionary<string, object> args = RunWorkflow("GetExcelData.xaml");
            DataTable dataTable =  (DataTable) args["out_テーブルデータ"];

            // TypeInto で使う要素名の配列
            string[] columns = new string[] {"苗字", "名前", "会社名", "部署", "住所", "メールアドレス", "電話番号"};

            // 同時実行タスクの最大数を 7 （テキストボックス数分）に設定
            ParallelOptions parallelOptions = new ParallelOptions();
            parallelOptions.MaxDegreeOfParallelism = 7;

            // clickOptions を渡して DelayBefore, DelayAfter を変更
            screen.Click(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge.開始, clickOptions);

            foreach(DataRow row in dataTable.Rows) {
                // テキストボックスの入力を並行で行う
                Parallel.ForEach(columns, parallelOptions, x =>
                {
                    // typeIntoOptions を渡せるように修正
                    screen.TypeInto(x, typeIntoOptions.WithText(row[x].ToString()));
                });
                // clickOptions を渡して DelayBefore, DelayAfter を変更
                screen.Click(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge.登録, clickOptions);
            }
        }
    }
}
```

以下、要点のみ説明します。

**「実行前の待機時間(Delay After)」, 「 実行後の待機時間(Delay Before)」の調整**

クリックや文字を入力アクティビティに該当するメソッドのプロパティを変更することができます。変更は各メソッド毎に用意されている ``メソッド名Options`` というクラスを用いて行います。今回のコードでは、``Click`` と ``TypeInto`` が該当するのでそれぞれ、``ClickOptions``、``TypeIntoOptions`` クラスを使います。

```csharp
// TypeInto のプロパティ (DelayBefore と DelayAfter を 0秒にする)
public TypeIntoOptions typeIntoOptions => new TypeIntoOptions() {
    DelayBefore = 0,
    DelayAfter = 0
};

// Click のプロパティ (DelayBefore と DelayAfter を 0秒にする)
public ClickOptions clickOptions => new ClickOptions() {
    DelayBefore = 0,
    DelayAfter = 0
};
```

メソッドの第二引数で渡してあげると設定値に基づいて動作するようになります。

```csharp
// clickOptions を渡して DelayBefore, DelayAfter を変更
screen.Click(Descriptors.Chrome__Rpa_Challenge_app.Chrome__Rpa_Challenge.開始, clickOptions);
```
``TypeInto`` メソッドには ``TypeInto(Descriptorsのクラス, 入力する文字列, TypeIntoOptions)`` のパターンがなかったため書き方を変更しています。

第一引数にオブジェクトリポジトリの要素名の文字列、第二引数に ``TypeIntoOptions`` を指定しつつ ``WithText`` で入力する文字列も渡しています。

```csharp
// typeIntoOptions を渡せるように修正
screen.TypeInto(x, typeIntoOptions.WithText(row[x].ToString()));
```

**文字入力の並列実行**
RPA Challenge の爆速化といえば、``並列`` アクティビティによる文字入力の同時実行です。C# では ``Parallel`` というその名もズバリなクラスが用意されているのでこちらを使って同時実行を実現しています。

``ParallelOptions`` を使うと並列実行の同時タスクの最大数を設定できます。こちら使わなくてもそこまで速度に影響はなかったのですが念のため入れています。

```csharp
// using ディレクティブへの追加が必要
using System.Threading.Tasks;

// TypeInto で使う要素名の配列
string[] columns = new string[] {"苗字", "名前", "会社名", "部署", "住所", "メールアドレス", "電話番号"};

// 同時実行タスクの最大数を 7 （テキストボックス数分）に設定
ParallelOptions parallelOptions = new ParallelOptions();
parallelOptions.MaxDegreeOfParallelism = 7;

// テキストボックスの入力を並行で行う
Parallel.ForEach(columns, parallelOptions, x =>
{
    // typeIntoOptions を渡せるように修正
    screen.TypeInto(x, typeIntoOptions.WithText(row[x].ToString()));
});
```

# 実行してみる

約50秒かかっていたものが 4秒台になりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3322296/ac4dbed3-373e-00a7-62a6-33a60fa48c54.png)

# おわりに
[プロセス爆速化のためのTIPS](https://www.uipath.com/ja/community-blog/tutorials/accelerate-processing) では平均 1824.8 ミリ秒という驚異的な数値が出ていますが、今回のリファクタリングでは 4秒を切ることが出来ませんでした。精進します。

皆さんも是非コード化されたオートメーションをお試しください！