Windowsでは全ての仕事や窓に名前を付け,各アプリケーションの処理の割り込みを常時監視しています。仕事の切替やエクスプローラがいつでも最優先(Realtime_Priority_Class)で動かないとOSとして正常に機能しないため,一つのプログラムを単独で走らせることができないのです。その意味ではDISK-BASICやDOSのようなシングルタスクOSの方が望ましいのですが,内部クロックの参照やハードウェアの制御が困難になりますし,周辺機器がWindows以外で動作保証されないことも多くなりました。
最近日本でも主流となっているIBM PC/AT互換機では,ハードウェアのINT 8割り込みで18.2Hzのタイマを使用しますので,直接これを利用すると55ms程度の精度しか得られないことになります。例えばVBのTimer関数は小数点以下の秒数を返しますので1ms単位まで測定できているように錯覚しがちですが,その精度はせいぜい55ms程度であることに注意する必要があります。
ところがWindows API関数のGetTickCountやTimeGetTimeを利用すると約10msで関数が更新され,かなり高精度になります。
Private Declare Function GetTickCount _ Lib "kernel32" () As Longというオマジナイと共に
Dim i, j For i = 1 to 20 j = GetTickCount Do while j = GetTickCount Loop Print j; "ms" Next iのようなプログラムをフォームのクリックで実行してみてください。
さらに,QueryPerformanceCounterという関数を利用することもできます。この関数は桁が多すぎてLong型変数に入らず,通貨型変数Currencyに格納して使います。この関数は秒単位を返しませんので,QueryPerformanceFrequencyで割った値を利用します。他の変数と共に
Private Declare Function QueryPerformanceCounter _ Lib "kernel32" (lpPerformanceCount As Currency) As Long Private Declare Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As Currency) As Longのように宣言しておきます。0で割らないように注意し,例えば解答のキーを押した時間を測るなら
Sub ProfileStart(secStart As Currency) If secFreq = 0 Then _ QueryPerformanceFrequency secFreq QueryPerformanceCounter secStart End Sub Sub ProfileStop(secStart As Currency, _ secTiming As Currency) QueryPerformanceCounter secTiming If secFreq = 0 Then secTiming = 0 Else secTiming = (secTiming - _ secStart) / secFreq End If End Sub Private Sub cmdStart_Click() 'スタートボタンを押す ProfileStart sec i = i + 1 '音を提示するなら,ここに mciExecute を挿入する End Sub Private Sub cmdAns_Click() '解答ボタンを押す ProfileStop sec, secOut secTime(i, j) = secOut j = j + 1 End Subのように使えます。ハードウェアにもよりますが,さらに高い精度が得られます。
「速い」ことと「速く感じる」ことは必ずしも同じではありませんが,プログラムの高速化の技法は高精度化のヒントとなります。現在はUnicodeへの移行期ですので今後は不透明ですが,VBの場合は整数型変数Integerが16ビットで処理されるためLong型より遅いと言われます(矢沢1998)。同様の心配が残りますが,ファイルの書き込みが必要な場合はテキストでもバイナリ操作用のPutを使う方がWriteよりも高速だという報告もあります(Craig & Webb 1997)。また,マウスの座標検出は結構時間がかかるようで,反応の取り込みにはキーボードを使った方が安全なようです。画面上のオブジェクトが複雑に配置されている場合,マウスでの入力が目に見えて遅くなり驚いた経験があります。さらに,余計な条件分岐を減らし,エラー処理もカットしてしまいましょう。特にGoSubでいわゆる「スパゲッティプログラム」を作ってしまうと決定的に遅くなるようです(Microsoft 1998)。Learning Editionではネイティブコードのコンパイルができないことや,視覚刺激提示をカラーで行う場合には専用タキストスコープのCRTディスプレイでさえ最小提示時間が10ms程度(ISEL-IS701C)であることにも注意すべきでしょう。
なおWindowsの「DOS窓」と「DOSモード」は全く別物ですし,Windows 3.1はOS自体がMS-DOS上のプログラムで,それぞれ根本的に対策が異なると考えられます。特に3.1でのタイマ使用には注意が必要で,本家Microsoft (1998)も 'In no sense can Microsoft Windows (3.1) be considered a "real-time" system. It is a message-driven, event-polling system, with nonpreemptive scheduling.' と警告しています。市販の実験用ソフトウェアはたとえ3.1対応でも,95以降を使う方が安全かもしれません。