Excelマクロでは、無駄な再計算でマクロの実行速度を落とさないために、実行中はApplication.Calculationの自動計算をOFFにするコードを記述することがあります。
PowerShellでこのプロパティを操作したときも、実行速度に影響があるか検証してみました。
検証手順
PowerShellのScript(*.ps1)でExcelに、数値と計算式を10000行3列、設定します。
下記の2パターンをそれぞれ10回テストして、実行時間の平均値を求めます。
パターンNo. | 検証パターン | Application.Calculation | 補足 | 数値セル | 計算式セル |
---|---|---|---|---|---|
1 | 自動計算 ONの状態 | (PowerShellのScript内で未設定) | Excelファイルの設定の初期値のままとする。 | 10000行 (A1~A10000 セル、B1~B10000) | 10000行 (C1~C10000セル) |
2 | 自動計算OFFの状態 | xlCalculationManual | 意図的にPowerShellのScript内で意図的にOFFにする。 処理の最後でONにする。 | 10000行 (A1~A10000 セル、B1~B10000) | 10000行 (C1~C10000セル) |
なお、Excelファイルの初期値とは、Excelファイルの下記の部分を「自動」としたケースです。
PowerShellの処理時間については下記のように開始時刻と終了時刻を出力させ、差分の実行時間の平均を求めます。
※下のキャプチャはPowerShellのScriptの作成時のイメージです。
Application.Calculationの再計算を十分に検証するため、PowerShellのScriptは下記の処理順とします。
- C列には「=A列+B列」の数式を格納する
- A列に値を格納する
- B列に値を格納する
下のキャプチャは実行した際にできる、実行結果のExcelファイルのイメージです。
※なお、通常はC列は計算結果が表示されますが、分かりやすさの為、上記のキャプチャは数式を表示しています。
なお、そのほかの条件はPCのスペック等含めて、同じにしています。
想定する結果
自動計算時
C列の数式を入力した際に、A列B列に値はないけど、一度数式が計算される想定です。
また、その後にA列B列の数値が入力された際にも、C列の数式が再計算される想定です。
なので、頻繁に数式を再計算して、処理速度が激遅の予測です。
手動計算時
C列の数式はループ終了時にまとめて再計算される想定です。
なので、おそらく処理速度は早い予測です。
ソースコード
使用したソースコードは下記のとおりです。
$excel.Calculationの部分(24行目、41行目あたり)をコメントアウトしたり、アンコメントしたりして検証します。
# 開始時刻
$startTime = (Get-Date)
Write-Host "StartTime : " $startTime.ToString("HH:mm:ss.fffffff")
$excel = New-Object -ComObject Excel.Application
$book = $null
$excel.Visible = $false
$excel.DisplayAlerts = $false
$excel.ScreenUpdating = $false
$fileName = "Book1.xlsx"
$filePath = (Convert-Path .) + "/" + $fileName
$book = $excel.Workbooks.Open($filePath)
$sheet = $book.Sheets("Sheet1")
$Calculation = "microsoft.office.interop.excel.XlCalculation" -as [type]
# 自動計算 OFF
$excel.Calculation = $Calculation::xlCalculationManual
# 負荷をかける処理
for ( $i=1; $i -le 10000; $i++){
# C列:計算式の入力(A列+B列) ※再計算の確認のため、先に数式を用意しておく
$formula = "=A" + $i + "+B" + $i
$sheet.Cells.Item($i,3).Formula = $formula
# A列
$sheet.Cells.Item($i,1).Value = $i
# B列
$sheet.Cells.Item($i,2).Value = $i + 1
}
# 自動計算 ON
$excel.Calculation = $Calculation::xlCalculationAutomatic
$excel.ScreenUpdating = $true
[void]$book.Save()
[void]$book.Close($false)
[void][System.Runtime.Interopservices.Marshal]::ReleaseComObject($book)
[void]$excel.Quit()
[void][System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel)
# 終了時刻
$endTime = (Get-Date)
Write-Host "EndTime : " $endTime.ToString("HH:mm:ss.fffffff")
# 時間差
Write-Host "TimeSpan : " ($endTime - $startTime).ToString("")
Pause
XlCalculation 列挙値
XlCalculationについては3つの値が設定可能ですが、今回は意味の補足に留めておきます。
詳しくはMicrosoftのドキュメントを参照してください。
設定値 | 値 | 説明 |
---|---|---|
xlCalculationAutomatic | -4105 | Excel が再計算を制御します。 |
xlCalculationManual | -4135 | ユーザーが要求すると、計算が完了します。 |
xlCalculationSemiautomatic | 2 | Excel が再計算を制御しますが、テーブル内の変更は無視します。 |
実行結果(速度測定)
初期設定
数字、数式を格納する対象Excelファイルの計算方法の設定の初期値は「自動」です。
速度測定結果の一覧
速度測定は各々10回実施しました。記事が長くなるためキャプチャは割愛します。
(経過時間の記載の形式は「HH:mm:ss.fffffff」です)
実行回数 | 自動計算ONの状態 (PowerShellのScript内で未設定の場合) | 自動計算OFFの状態 (xlCalculationManualを設定の場合) |
---|---|---|
1回目 | 00:01:57.9379781 | 00:01:35.5133327 |
2回目 | 00:02:17.8109704 | 00:01:36.9314456 |
3回目 | 00:02:39.6962527 | 00:01:35.9776432 |
4回目 | 00:02:15.9363111 | 00:01:42.2736822 |
5回目 | 00:02:38.7812819 | 00:01:34.7567951 |
6回目 | 00:02:23.5837214 | 00:01:57.8079433 |
7回目 | 00:02:36.4546489 | 00:01:32.2901524 |
8回目 | 00:02:39.3424819 | 00:01:34.1461086 |
9回目 | 00:02:35.1502410 | 00:01:38.9322428 |
10回目 | 00:02:27.9159061 | 00:01:40.2430028 |
平均値、最小値、最大値は下記のとおりです。
実行回数 | 自動計算ONの状態 (PowerShellのScript内で未設定の場合) | 自動計算OFFの状態 (xlCalculationManualを設定の場合) | 差異 |
---|---|---|---|
平均値 | 約00:02:27 | 約00:01:39 | 約49秒スピードアップ |
最小値 | 00:01:57.9379781 | 00:01:32.2901524 | 約26秒スピードアップ |
最大値 | 00:02:39.6962527 | 00:01:57.8079433 | 約42秒スピードアップ |
結論
結果として、処理実行中はxlCalculationManualに設定したほうが、平均値、最大値、最小値とも早い結果となりました。
PowerShellでもApplication.Calculationの設定を意識したほうがよさそうです。
参考情報
下記の環境で作成・実行しております。
No. | 環境 | バージョン |
---|---|---|
1 | OS | Windows10 |
2 | PowerShell | 5.1 |
以上です。
コメント