スタッフの五十島です!
今回は、Officeスクリプトのループ処理の注意点についてご紹介いたします。
for等のループ処理内でのパフォーマンス警告
Officeスクリプトは、ExcelなどのMicrosoft Office製品で自動化スクリプトを作成するための便利なツールです!しかし、実行内容によってはパフォーマンスが著しく低下することがあります・・・
特に、ループ内でセルの読み込みや書き込みを行うと、大量のセルや多数のループ回数がある場合にはスクリプトの実行がかなり遅くなることがあります。
実際にfor文の中にgetValueメソッドを記述すると、オレンジの波線がかかり、「Invoking read methods inside of a loop could lead to slow performance of the script. For more information, please visit https://aka.ms/office-scripts-performance」という警告が表示されます。
そこで、getValueメソッドを使わずにパフォーマンスを向上させる方法として、getUsedRangeメソッドとgetValuesメソッドをご紹介します!
getUsedRangeを使うことで、シート上で使用されているセルの範囲を簡単に取得できます。そして、getValuesは、取得した範囲の値を一度に配列として取得できます。
このアプローチを採用することで、getValueメソッドをループ内で使用する必要がなくなり、スクリプトの実行時間を短縮することができます!
※ただし、getValuesメソッドを使用する場合は、取得した時点の値からリアルタイムで更新されないため、注意が必要です。
参考:Office Scripts のパフォーマンスの改善 – Office Scripts | Microsoft Learn
パフォーマンスの差異について検証
実際に各メソッドの実行時間にどの程度の差が出るのか検証してみました!
function main(workbook: ExcelScript.Workbook) {
for(let i=0;i<10;i++){
const start = performance.now();
for(let j=0;j<1000;j++) {
const tmp = workbook.getActiveWorksheet().getCell(j, 0).getValue();
}
const end = performance.now();
workbook.getActiveWorksheet().getCell(i, 1).setValue(end - start);
}
}
function main(workbook: ExcelScript.Workbook) {
const usedRange = workbook.getActiveWorksheet().getUsedRange();
const rangeValues = usedRange.getValues();
for(let i=0;i<10;i++){
const start = performance.now();
for(let j=0;j<1000;j++) {
const tmp = rangeValues[j][0];
}
const end = performance.now();
workbook.getActiveWorksheet().getCell(i,2).setValue(end - start);
}
}
どちらのスクリプトも、セルの値を1000回読み込む時間を10回計測するスクリプトになります。
この比較の参考結果は以下のようになりました。
getValue | getUsedRange&getValues | |
1回目 | 3515.3 | 0.8 |
2回目 | 3305.4 | 0.4 |
3回目 | 3192.7 | 0.3 |
4回目 | 3053.3 | 0.2 |
5回目 | 3064.7 | 0.1 |
6回目 | 3050.2 | 0.1 |
7回目 | 2909.6 | 0.1 |
8回目 | 3156.7 | 0.4 |
9回目 | 3352.7 | 0.2 |
10回目 | 3335.8 | 0.2 |
平均時間 | 3193.64 | 0.28 |
こちらの結果から、getValuesメソッドを使った場合は配列に格納した値を読んでいるため高速ですが、getValueメソッドでは都度セルの値を読み取るため実行時間が遅いことがハッキリとわかりました!
なお、(私の環境では)1回のセルの読み込みは平均で3ms程度であると推測されるため、大量のセル処理を行わない限り、警告を無視しても影響は少ないといえるでしょう(笑)
getUsedRangeとgetValues
メソッドを使って、Officeスクリプトのパフォーマンスを向上させる方法をご紹介しました。
forなどのループ内でセルの値を扱う処理を大量に行う場合、このアプローチで実行時間を短縮することができますので、ぜひお試しください!