人気ブログランキング | 話題のタグを見る
Excel VBAでのマルチスレッド
■議題
ExcelVBAでマルチスレッドができるか?

■環境
Office 2010
Windows 7(64bit)

■手っ取り早い結論
スレッドはつくれたがやるな



■基本的なお話
ExcelのオブジェクトはSTAのCOMです。なので、複数のスレッドからアクセスしたところで、COMのなかでシリアライズされるので、並行に動作しません。

もし、Excelのセルの描画などを複数スレッドで同時にして速度改善とか思っているなら無駄です。あきらめてください。

参考:
Office でのスレッドのサポート


■ExcelVBAでCreateThreadができるか?
では、Excelのオブジェクトの操作はあきらめたとしてExcelVBAにおいてWindowsAPIのCreateThreadでスレッドが作成できるか検証します。


Private Type SECURITY_ATTRIBUTES
nLength As Long
lpSecurityDescriptor As Long
bInheritHandle As Long
End Type

Declare Function CreateThread Lib "KERNEL32" _
(ByRef lpThreadAttributes As SECURITY_ATTRIBUTES, _
ByVal dwStackSize As Long, _
ByVal lpStartAddress As Long, _
ByVal lpParameter As Long, _
ByVal dwCreationFlags As Long, _
ByRef lpThreadId As Long) As Long

Declare Function CloseHandle Lib "KERNEL32" _
(ByVal hObject As Long) As Long

Declare Function WaitForSingleObject Lib "KERNEL32" _
(ByVal hHandle As Long, _
ByVal dwMilliseconds As Long) As Long

Declare Function CoInitialize Lib "OLE32" _
(ByVal pvReserved As Long) As Long

Private Declare Sub CoUninitialize Lib "OLE32" _
()

Declare Sub Sleep Lib "KERNEL32" _
(ByVal dwMilliseconds As Long)

Const INFINITE = &HFFFFFFFF ' Infinite timeout

Dim hThread As Long
Dim idThread As Long
Dim mTargetSheet As Worksheet
Dim mThreadData As String

Public Sub Test()
Dim i As Long
Dim att As SECURITY_ATTRIBUTES
att.nLength = Len(att)
Set mTargetSheet = Sheet1
For i = 1 To 10
hThread = CreateThread(att, 0&, AddressOf ThreadProc, i, 0&, idThread)
Debug.Print "Handle=" & hThread, "Id=" & idThread, "i=" & i

n = WaitForSingleObject(hThread, INFINITE)

Debug.Print mThreadData

CloseHandle hThread

Next i
End Sub

Private Function ThreadProc(ByVal n As Long) As Long
Dim nRet As Long
'nRet = CoInitialize(0)
Sleep 1000
'Debug.print ですら堕ちる
'Debug.Print Now() & " THREAD" & n & ":" & i & " nRet:" & nRet
mThreadData = Now() & " THREAD" & n & ":" & i & " nRet:" & nRet

' EXCELオブジェクトに触ると堕ちる
'mTargetSheet.Cells(i, 1).Value = "test"
'Call CoUninitialize

ThreadProc = 0
End Function




このコード非情に不安定です。
作成したスレッド内でブレイクを掛けると堕ちます。デバッグできません。
作成したスレッド内でDebug.PrintやExcelのオブジェクトを操作しようとすると堕ちます。
このプログラムをちょっといじって、さらにスレッドを作成すると堕ちます。

結論として、VBAでCreateThreadを行うのはやめておいたほうがいいです。


■別解1
Multi-threaded VBAでは別のアプローチを行っています。
詳細は該当ページのExcelをダウンロードして参照していただけるとわかりますが、VBAからVBScriptを起動してそのVBScriptで時間のかかる処理を行い、結果をGetObject("Excel.Application")で取得したExcelオブジェクトを経由してセルに格納しています。

ただし、これはマルチスレッドじゃなく、マルチプロセスですね。

■別解2
C++なりC#で実装しちゃたほうが楽でしょう
by mima_ita | 2012-08-27 23:25 | VBA
<< Windwodsバッチファイル... ExcelVBAのソースを全部消す >>



実験ですお

by mima_ita
検索
カテゴリ
最新の記事
.NET4.5におけるasy..
at 2014-07-02 00:46
.NETでTwitterを検..
at 2014-06-29 00:49
Redmineのプラグインで..
at 2014-06-28 03:29
IO.popenのwrite..
at 2014-06-28 03:25
RedmineのWikiでU..
at 2014-06-28 03:16
以前の記事
最新のトラックバック
その他のジャンル
ブログパーツ