none
データ収集アプリケーションのボトルネック処理を見つけ出すには RRS feed

  • 質問

  • こんばんは。

    C#で次のようなデータ収集アプリケーションを作っています。
    ・Windows Formを使用
    ・SNMPの外部DLLによりOIDを指定すると値を返してくる
    ・OIDごとに値を表示するTextBoxがあり、そこに値を表示する
    ・表示とは別にテキストファイルにCSV形式で取得時間と各OIDごとの値を追記していく(StreamWriter)
    ・データ取得間隔は1秒に設定している。

    アプリケーションはstaticなOID配列を設定したら、それを下にTimer1.Tickの中で返り値を表示、記録しています。

    Timer1.Tickは現在の時間を表示するためにも使っているので、Intervalを100msecにして現在の時間が表示されている時間と異なるときに、SNMP GET、値表示、データ記録をしています。

    このアプリケーションが、数時間動かしていると固まってしまうことがあります。おそらく1秒以内に処理が終了しなかったときに、1秒後の処理が重なってしまい、特にSNMPのGetプロセスで不整合が起きたり、FileへのIOで書き込み終わっていない等のトラブルだと思うのですが、何処で時間がかかっているのか調べたいです。

    ASP.NETのページでDebugを有効にすると、各イベント間にかかった時間が表示されますが、Windows Formでもそのようなものはありますか?
    キーワードがわからなかったので教えていただけますでしょうか。

    よろしくお願いします。

     

    2006年9月20日 10:42

回答

  • 1回50秒かかる処理があります。

    このうち10秒かかる処理を10回分まとめて行うようにしました。

    変更前は50秒*10で10回の処理に500秒掛かっていました。

    変更後の処理は(50秒-10秒)*10回 + (10秒*10回)となり、500秒掛かります。

    ただしファイルオープンクローズなどの処理が1回で済むことを考えると、10秒の処理は8秒で済みます。

    (50秒-10秒)*10回 + (8秒*10回) 合計で480秒で済むようになりました。

    #全体の処理速度は向上

    ただし10回の処理としてみたときには

    40, 40, 40, 40, 40, 40, 40, 40, 40, 40 + 80(ログ出力)

    最後の処理だけ40+80で120秒掛かってしまいます。

    これでは1回あたりの処理を60秒以内に終わらせることが出来ない回があるということになります。

    お分かりいただけましたか?

    2006年9月21日 11:07
  • 中さん、回答ありがとうございます。

    わからない部分がわかったような・・・。
    つまりスレッドを使ってないアプリケーションだと、いくら10秒に一度、FileWriteのサブルーチンを処理するようにしていても、この処理が終わらないといかなる処理にも移れない、ということで、

    新 0.4, 0.4, 0.4....1.4,0.4,0.4,.......,0.4,1.4
                ^------------------------^
                   書き込みが終わるまで10秒の余裕

    というのは間違いで、1秒以内に書き込みが終わる必要があるということ
    ですか?

    そうであれば、たしかにスレッドでバックグラウンドでやればハングしなくなりますね。

    基本的なことが理解できました。ありがとうございました。

    2006年9月21日 11:58

すべての返信

  • ツールにある「パフォーマンス ツール」?

    ↓...orz

    2006年9月20日 11:27
    モデレータ
  • ただこの問題はボトルネックを探すのではなく、処理中に後続のタイマー処理を実行させないようにするほうが先決でしょう?

    もしも実行可能でないといけないのであれば、スレッドを何本かあげて並行処理できるようにするべきでしょう。

    とりあえずパフォーマンスよりはそっちが先だと思います。

    2006年9月20日 14:11
  • trapemiyaさん、中さん、回答ありがとうございます。
    パフォーマンスツールって、C# Expressで使えますか? ツールメニューを探しましたが見つかりませんでした。

    目標は少なくとも一秒に一度SNMP Getを送信するようにしたいと思っているので、Threadを使用したほうがいいのはわかっているのですが、まだ未挑戦な作り方なので見通しが立ってません。できましたらアドバイスをいただけますか?

    Threadクラスで一秒ごとにインスタンスを順番に作成してその中でSNMP Get、表示、記録をする。記録は正しい順番で行う必要があるので、順番が狂わないようにする必要がある?

    または、今一番ボトルネックになってると思っているStreamWriterの処理をもっと早い処理にする(って方法はありますか?)。一秒ごとに記録時間を含めた28項目の数値データを記録できればOKなのですが。


    2006年9月20日 15:27
  • >パフォーマンスツールって、C# Expressで使えますか? ツールメニューを探しましたが見つかりませんでした。
    使えませんね。

    多分VSTE以上だと思います。

    >目標は少なくとも一秒に一度SNMP Getを送信するようにしたいと思っているの
    >一秒ごとに記録時間を含めた28項目の数値データを記録できればOKなのですが。

    目標が2つありますが、記録を1秒以内に完結させる必要があるのですか?

    たぶんないですよね?

    そこをQueueを使うようにしたりすればいいでしょう。あとはいろいろあるんだけどもっと細かい話にならないとわからないですね。がんばってください。

     

    2006年9月20日 15:36
  • 中博俊さん、回答ありがとうございます。

    記録は一秒以内に終わる必要はありません。

    早速スレッドのやり方で作り始めたのですが、ちょっと考えてみたら、1秒に一回FileIOをするのではなくて10回分のデータを配列に持って10秒に一度記録で大丈夫なのではないかと思って、スレッドを使わず作成しましたがやっぱりFreezeします。

    現在は、10秒に一度記録する部分をスレッドにして試験中ですが、他の理由でFreezeしているのかもしれません。

    Freezeの仕方が、Windows Formの表示が何もなくなり、ウィンドウを閉じるボタンを押すと「アプリケーションから応答がありません」というおなじみのダイアログが出てしまい、イベントログにもHang Upとしか記録されていません。

    C#Expressだけで書いたプログラムで、例外も返さずにハングすると言うのは、外部DLL(これもC#)の部分でエラーが起こっているのでしょうか。

    2時間に一度くらいの割合ですが必ず出るバグです。どうやってデバッグすればよいかなにかアドバイス等いただければ幸いです。

    2006年9月21日 7:19
  • なにも有効な手を打たずに

    >1秒に一回FileIOをするのではなくて10回分のデータを配列に持って10秒に一度記録で大丈夫なのではないかと思って、スレッドを使わず作成しましたがやっぱりFreezeします。

    すると、10回に1回回ってくる書き込みのタイミングが遅くなるだけです。


    0.5, 0.5, 0.5....0.5


    0.4, 0.4, 0.4....1.4

    (あくまで時間はイメージですが)

    >ウィンドウを閉じるボタンを押すと「アプリケーションから応答がありません」というおなじみのダイアログが出てしまい、イベントログにもHang Upとしか記録されていません。

    これはハングアップしているのではなく、一生懸命待ち受けているからですよね?

    >どうやってデバッグすればよいかなにかアドバイス等いただければ幸いです。

    近道はありません。

    スレッドプログラムを少し勉強しないと回避不能だと思います。

    2006年9月21日 9:28
  •  中博俊さん、回答ありがとうございます。
    新 0.4, 0.4, 0.4....1.4,0.4,0.4,.......,0.4,1.4
                ^------------------------^
                   書き込みが終わるまで10秒の余裕

    このように10秒の余裕が出来ませんか?コードは下のような感じです。
    public partial class SNMPGet:Form
    {
     private string DataString[]=new string[10];
     private int counter =0;

     private void timer1_Tick(object sender, EventArgs e)
     {
       if (LabelCurrentTime.Text != DateTime.Now.ToString())
       { LabelCurrentTime.Text = DateTime.Now.ToString(); }
     }

     private void LabelCurrentTime_TextChanged(object sender, EventArgs e)
     {
       long Value =SNMP.Get(OID);
       DataString[counter]=Value.ToString();
       counter+=1;
       if (counter==10)
       { counter=0; FileWrite(); }
     }

     private void FileWrite()
     {
       for(int i=0;i<10;i++)
       { ファイル書き込み(DataString[ i ]); }
     }
    }

     counterが10になったときしかFileの書き込みをしないのですから、1秒間しか書き込み時間がなかったものが10秒間の余裕に増えてるように思うのですが、間違っていますでしょうか。
    中さんの仰るとおり、たしかに、現在FileWriteの呼び出しをスレッドで行って実験をしてるのですが、そっちは3時間ほど固まってません。

    どう考えればよいのか、教えていただけませんか?何度もしつこくてすみません。

    2006年9月21日 10:33
  • 1回50秒かかる処理があります。

    このうち10秒かかる処理を10回分まとめて行うようにしました。

    変更前は50秒*10で10回の処理に500秒掛かっていました。

    変更後の処理は(50秒-10秒)*10回 + (10秒*10回)となり、500秒掛かります。

    ただしファイルオープンクローズなどの処理が1回で済むことを考えると、10秒の処理は8秒で済みます。

    (50秒-10秒)*10回 + (8秒*10回) 合計で480秒で済むようになりました。

    #全体の処理速度は向上

    ただし10回の処理としてみたときには

    40, 40, 40, 40, 40, 40, 40, 40, 40, 40 + 80(ログ出力)

    最後の処理だけ40+80で120秒掛かってしまいます。

    これでは1回あたりの処理を60秒以内に終わらせることが出来ない回があるということになります。

    お分かりいただけましたか?

    2006年9月21日 11:07
  • 中さん、回答ありがとうございます。

    わからない部分がわかったような・・・。
    つまりスレッドを使ってないアプリケーションだと、いくら10秒に一度、FileWriteのサブルーチンを処理するようにしていても、この処理が終わらないといかなる処理にも移れない、ということで、

    新 0.4, 0.4, 0.4....1.4,0.4,0.4,.......,0.4,1.4
                ^------------------------^
                   書き込みが終わるまで10秒の余裕

    というのは間違いで、1秒以内に書き込みが終わる必要があるということ
    ですか?

    そうであれば、たしかにスレッドでバックグラウンドでやればハングしなくなりますね。

    基本的なことが理解できました。ありがとうございました。

    2006年9月21日 11:58