Excel VBAのシングルスレッド特性に関する備忘録


## はじめに

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/03fe48e0-3046-46dc-a9fa-b175ad72a848.png)
Excel VBAはMicrosoft Officeアプリケーションの自動化に広く使用されていますが、その重要な特性の一つとして「シングルスレッド」があります。この記事では、Excel VBAがシングルスレッドであることの意味、それによる制限事項、そして実務での対処法について解説します。

## VBAとシングルスレッドの基本

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/b7eb0f2d-3843-4912-b148-95271c3b5102.png)

VBA（Visual Basic for Applications）はExcelなどのOfficeアプリケーションに組み込まれたプログラミング言語です。VBAは**シングルスレッド**で動作します。これは以下のことを意味します：

- 一度に1つの処理しか実行できない
- 複数の処理を並列に実行できない
- 処理が完了するまで次の処理に進まない

他の現代的なプログラミング言語では、マルチスレッドやマルチプロセス処理が一般的になっていますが、VBAはその設計上の制約からシングルスレッドのままです。

## シングルスレッドによる主な制限事項

![vba-limitations.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/2f3c1291-71dc-49f2-9bd9-1f44b4f306df.png)

### 1. 処理速度の制限

大量のデータを処理する場合、シングルスレッドであることが大きなボトルネックになります。例えば：

- 10万行のデータをループ処理する場合、すべての処理が順番に行われる
- CPUのマルチコア性能を活かせない
- 処理中はExcelが「応答なし」状態になることがある

### 2. UIの応答性低下

VBAマクロの実行中は、Excelのユーザーインターフェースが応答しなくなります：

- 長時間実行されるマクロでは、ユーザーは操作を中断できない（Ctrl+Breakを除く）
- 進捗状況を示すUIの更新も同じスレッドで行われるため、表示が滞る
- ユーザー体験の低下につながる

### 3. 外部リソースとの連携の難しさ

外部のシステムやサービスとの連携時に問題が生じることがあります：

- データベース接続やWebサービスへのリクエストを待つ間もスレッドがブロックされる
- 非同期処理の実装が困難
- タイムアウト管理が複雑になる

## 実務での対処法と注意事項

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/4829ccc0-02da-4b9a-bf96-be5b5b3ee000.png)

### 1. 処理の最適化

```vba
' 非効率な例
Sub 非効率なコード()
    Dim i As Long, j As Long
    For i = 1 To 10000
        For j = 1 To 100
            Cells(i, j).Value = i * j
        Next j
    Next i
    ' セルを1つずつ更新（非常に遅い）
End Sub

' 最適化した例
Sub 最適化したコード()
    Dim i As Long, j As Long
    Dim データ配列() As Variant
    ReDim データ配列(1 To 10000, 1 To 100)
    
    ' 配列にデータを格納
    For i = 1 To 10000
        For j = 1 To 100
            データ配列(i, j) = i * j
        Next j
    Next i
    
    ' 一度にセルに書き込み
    Range("A1").Resize(10000, 100).Value = データ配列
End Sub
```

### 2. Application.ScreenUpdating の活用

```vba
Sub 画面更新の制御()
    Application.ScreenUpdating = False ' 画面更新を一時停止
    
    ' ここに処理を記述
    
    Application.ScreenUpdating = True ' 画面更新を再開
End Sub
```

### 3. 進捗状況の表示

```vba
Sub 進捗状況表示の例()
    Dim i As Long, 合計 As Long
    合計 = 10000
    
    ' ステータスバーを使用
    Application.StatusBar = "処理を開始します..."
    
    For i = 1 To 合計
        ' 100回に1回進捗を更新
        If i Mod 100 = 0 Then
            Application.StatusBar = "処理中... " & Format(i / 合計, "0%") & " 完了"
            DoEvents ' UIの更新を許可
        End If
        
        ' ここに処理を記述
        
    Next i
    
    Application.StatusBar = False ' ステータスバーをリセット
End Sub
```

### 4. DoEventsの使用（注意が必要）

```vba
Sub DoEventsの例()
    Dim i As Long
    
    For i = 1 To 10000
        ' 処理
        
        If i Mod 100 = 0 Then
            DoEvents ' Windowsメッセージの処理を許可（UIの応答性向上）
        End If
    Next i
End Sub
```

**注意**: `DoEvents`は使用すると処理速度が低下する場合があり、過度に使用するとプログラムの挙動が予測できなくなることがあります。

### 5. 大規模処理の分割

長時間実行されるマクロは、可能な限り小さなタスクに分割することを検討しましょう：

- 一度に全データではなく、バッチ処理を検討する
- ユーザーに制御を返す機会を設ける
- 重要なポイントでデータを保存する

## シングルスレッドの代替手段

### 1. 外部プログラムの活用

より複雑な処理が必要な場合は、VBAから外部プログラムを呼び出す方法があります。

以下はシンプルな例です。プロセス間通信など、さまざまな方法が考えられますが、用途に応じて適切な手法を選択することが重要です。

```vba
Sub 外部プログラム呼び出し()
    Dim WshShell As Object
    Set WshShell = CreateObject("WScript.Shell")
    
    ' 外部プログラムを呼び出す
    WshShell.Run """C:\Path\To\Program.exe"" param1 param2", 1, True
    
    Set WshShell = Nothing
End Sub
```

### 2. Power Queryの活用

データ変換や読み込みには、Power Queryを使用することも検討できます：

- シングルスレッドの制約を受けない
- クエリエディタでのビジュアルな開発が可能
- 高速なデータ処理が可能

### 3. Power Automateの検討

Microsoft Power Automateを使用して自動化フローを構築することも選択肢の一つです：

- クラウドベースの処理が可能
- スケジュール実行やトリガーベースの実行が簡単
- 様々なサービスとの連携が容易

## まとめ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/1de24228-fde6-44d0-b0dc-1608dbdf4b56.png)

Excel VBAがシングルスレッドであることを理解し、その制限の中で最適なパフォーマンスを得るための対策を講じることが重要です。大量データの処理や複雑な処理が必要な場合は、VBAの代替手段も検討すべきでしょう。

VBAの知識は今でも多くの企業で価値がありますが、その制限を理解し、適切な場面で使用することが成功への鍵となります。

## 参考リンク

- [Microsoft VBA Documentation](https://docs.microsoft.com/en-us/office/vba/api/overview/)