Silverlight をインストールするには、ここをクリックします*
Japan変更|すべてのMicrosoft のサイト|サインイン
MSDN
|MSDN ライブラリ|デベロッパー センター|ダウンロード情報|開発ツール製品|コミュニティ|ご意見・ご要望|サイトマップ
MSDN Home > ステップ 7 > .NET アプリケーションの実装 基本知識編(Visual Studio 2005 / .NET Framework 2.0 対応版)  > DoEvents メソッドを使ったパフォーマンスの向上

ステップ 7 ハンズオン : DoEvents メソッドを使ったパフォーマンスの向上

Windows フォームにおけるパフォーマンスの向上 (非同期処理編)

マイクロソフト株式会社 デベロッパーマーケティング本部
デベロッパーエバンジェリスト 高橋 忍

最終更新日 2006 年 11 月 14 日

目標 重たい処理を実行する Windows フォームアプリケーションの作成
使用技術
  • Visual Basic .NET 2005
取り上げるトピックス
  • DoEvents メソッドを使ったときの Windows アプリケーションの動作の違いを確認する
前提知識
目次
サンプル アプリケーションの
完成品ダウンロード
Improve_performance_Winform2_vs2005.exe (exe 形式 / 42.8 KB)

DoEvents メソッドを使ったパフォーマンス テスト アプリケーションの作成

では、DoEvents メソッドのを使ったときのパフォーマンスの違いを確認するためのテスト アプリケーションを作成してみます。


Step 1 :

Visual Studio .NET 2005 を起動して、以下の設定で新規にプロジェクトを作成します。

プロジェクトの種類プロジェクトテンプレートプロジェクト名
[Visual Basic プロジェクト][Windows アプリケーション]PerformanceTest

Step 2 :

ツールボックスから Button Control を 1 つ、RadioButton コントロールを 2 つ、そして ListBox コントロールを 1 つをフォームに配置し、以下のようにプロパティを設定します。

コントロールIDプロパティ名設定値
Button1(Name)btnStart
Text開始
RadioButton1(Name)optDoEvents
TextDoEvents 処理
RadioButton2(Name)optSingle
Textパフォーマンス処理なし
checked(true)
ListBox1  

図 1. アプリケーション フォーム

図 1. アプリケーション フォーム


Step 3 :

btnStart をダブルクリックしてコードを表示します。「Windows フォームデザイナで生成されたコード」に続けて、アプリケーションの業務処理 (myProc) とリストボックスに記録する処理 (additem) を実装するため、以下のコードを追加します。業務処理に当たる myProc では、500ms (= 0.5 秒) のウェイトを持たせることで擬似的に重い処理を再現しています。処理を 1 回行うことに ListBox に記録をします。

    Private Sub myProc()
        Dim i As Integer
        For i = 1 To 5
            System.Threading.Thread.Sleep(500)
            Me.additem(i.ToString() & "回目の処理完了 " & Now.ToLongTimeString())
        Next
    End Sub

    Private Sub additem(ByVal strItem As String)
        Me.ListBox1.Items.Add(strItem)
    End Sub

続いて業務処理を起動するための処理を実装します。btnStart_click1 メソッドに以下のコードを追加します。ここでは、処理を開始する前にリストボックスを初期化し、ListBox に処理の開始を記録します。業務処理が終わったら処理の終了を記録します。

    Private Sub btnStart_Click(ByVal sender As System.Object, _
     ByVal e As System.EventArgs) Handles btnStart.Click
        Me.ListBox1.Items.Clear()
        Me.additem("start")
        Me.myProc()
        Me.additem("end")
    End Sub

Step 4 :

以上で、元になるアプリケーションの実装は完了です。では実際にビルトしてパフォーマンスのテストをしてみましょう。[ビルト] メニューから [ソリューションのビルト] を実行してアプリケーションをビルトします。問題がなければ、[Ctrl] キーを押しながら [F5] キーを押すか、[デバッグ] メニューの [デバッグなしで開始] をクリックします。

アプリケーションが起動したら、[開始] ボタンを押してみましょう。処理が開始されますが、リストボックスには何も表示されません。またウィンドウを移動しようとしてもできないことを確認してください。数秒たつと業務処理は完了しリストボックスには開始から終了までの記録が表示され、ウィンドウの移動も可能になります。

図 2. 基本アプリケーションを実行しても何も表示されない

図 2. 基本アプリケーションを実行しても何も表示されない

いかがですか?

今回は 5 回の処理ですが、これが数百回の処理であった場合を想像してみてください。アプリケーションがハングアップしたのか、処理を続けているのか判別ができないでしょう。これではアプリケーションとしては問題がありますね。


Step 5 :

では、ここに DoEvent 処理を追加しアプリケーションのパフォーマンスの改善を試みます。
アプリケーションのコードを表示し、MyProc メソッドに以下のコードを追加します。


    Private Sub myProc()
        Dim i As Integer
        For i = 1 To 5
            ' 以下のコードを追加
            If Me.optDoEvents.Checked Then
                Application.DoEvents()
            End If
            ' ここまで

            System.Threading.Thread.Sleep(500)
            Me.additem(i.ToString() & "回目の処理完了 " & Now.ToLongTimeString())
        Next
    End Sub

これにより、業務処理を実行する前に OS にたまっているイベントを実行することができます。


Step 6 :

DoEvents を使った改修が完了したので、実際にビルトして効果を確認します。

アプリケーションが起動したら、DoEvents のラジオボタンを選択してから [開始] ボタンを押してみましょう。今度は開始メッセージが表示され次々と処理完了のメッセージがリストボックスに追加されます。このときにウィンドウの移動をしてみると (一呼吸遅れるかもしれませんが) ウィンドウを移動することができます。

図 3. DoEvents メソッドによって処理経過を確認できる

図 3. DoEvents メソッドによって処理経過を確認できる

  • 解説
  • DoEvents メソッドを入れることで、イベントとしてためられていたリストボックスの表示処理や、ウィンドウの表示処理が実行されるため、少なくとも処理が続けられていることがわかります。また、スムースではないにせよウィンドウの移動などの処理も行うことができます。


Step 7 :

では、ここで DoEvents 処理の問題を確認してみます。

【イベント処理が重い場合】

Step 6 と同様に [開始] ボタンを押して処理を開始します。開始メッセージが現れたら、ウィンドウをドラッグしてウィンドウの移動をします。そのまま止めずにしばらく動かしてみてください。すると、アプリケーションの処理が進まずに途中で停止することが確認できるでしょう。

  • 解説
  • DoEvents を行った際にウィンドウの移動処理イベントがあった場合には、それを実行します。そしてそのウィンドウの移動処理が絶え間なく発生するため、いつまでたっても DoEvents 処理を終了することができないのです。つまりこの対処方法ではアプリケーション以外の処理の負荷に影響を受けやすいという欠点を持っているのです。

【業務処理がさらに重い場合】

次に myProc の Sleep の時間を 500 (ms) から 5000 (ms) に変更して実行してみましょう。これは業務処理がさらに重く時間のかかる処理になったことを意味します。

    
    Private Sub myProc()
        Dim i As Integer
        For i = 1 To 5
            ' 以下のコードを追加
            If Me.optDoEvents.Checked Then
                Application.DoEvents()
            End If
            ' ここまで

            System.Threading.Thread.Sleep(5000)
            Me.additem(i.ToString() & "回目の処理完了 " & Now.ToLongTimeString())
        Next
    End Sub
  • 解説
  • アプリケーションを実行すると、表示経過がなかなか更新されず、またウィンドウの移動処理も思うようにできないことがわかります。現在の実装では、あくまでも DoEvent を実行した際にのみ、たまったイベント処理が実行されるため、業務処理が重ければあまり効果は期待できないことがわかります。


まとめ

DoEvents の簡易な処理によってある程度のパフォーマンス改善を行うことができました。しかし、ケースによってはこの処理では不十分な場合もあるでしょう。ですからケースバイケースで対処方法を検討して選択することが必要です。


次は 『非同期処理を使ったパフォーマンスの向上』について説明します。


Microsoft